@dereekb/browser 13.2.2 → 13.3.1
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/index.cjs.js +400 -112
- package/index.esm.js +400 -112
- package/package.json +3 -3
- package/src/lib/service.d.ts +51 -2
- package/src/lib/vh100.d.ts +18 -0
- package/src/lib/window.d.ts +36 -0
package/index.cjs.js
CHANGED
|
@@ -6,13 +6,11 @@ var rxjs = require('rxjs');
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Creatse a new BrowserObjectURLRef.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
let browserUrl;
|
|
9
|
+
*/ function browserObjectUrlRef() {
|
|
10
|
+
var browserUrl;
|
|
12
11
|
/**
|
|
13
12
|
* Revokes the existing browser object URL, if one exists.
|
|
14
|
-
*/
|
|
15
|
-
function destroy() {
|
|
13
|
+
*/ function destroy() {
|
|
16
14
|
if (browserUrl) {
|
|
17
15
|
URL.revokeObjectURL(browserUrl);
|
|
18
16
|
}
|
|
@@ -25,128 +23,386 @@ function browserObjectUrlRef() {
|
|
|
25
23
|
return browserUrl;
|
|
26
24
|
}
|
|
27
25
|
return {
|
|
28
|
-
destroy,
|
|
29
|
-
getBrowserUrl: ()
|
|
26
|
+
destroy: destroy,
|
|
27
|
+
getBrowserUrl: function getBrowserUrl() {
|
|
28
|
+
return browserUrl;
|
|
29
|
+
},
|
|
30
30
|
createBrowserUrl: createBrowserUrl
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
35
|
+
try {
|
|
36
|
+
var info = gen[key](arg);
|
|
37
|
+
var value = info.value;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
reject(error);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (info.done) {
|
|
43
|
+
resolve(value);
|
|
44
|
+
} else {
|
|
45
|
+
Promise.resolve(value).then(_next, _throw);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function _async_to_generator(fn) {
|
|
49
|
+
return function() {
|
|
50
|
+
var self = this, args = arguments;
|
|
51
|
+
return new Promise(function(resolve, reject) {
|
|
52
|
+
var gen = fn.apply(self, args);
|
|
53
|
+
function _next(value) {
|
|
54
|
+
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
|
|
55
|
+
}
|
|
56
|
+
function _throw(err) {
|
|
57
|
+
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
|
|
58
|
+
}
|
|
59
|
+
_next(undefined);
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function _class_call_check(instance, Constructor) {
|
|
64
|
+
if (!(instance instanceof Constructor)) {
|
|
65
|
+
throw new TypeError("Cannot call a class as a function");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function _defineProperties(target, props) {
|
|
69
|
+
for(var i = 0; i < props.length; i++){
|
|
70
|
+
var descriptor = props[i];
|
|
71
|
+
descriptor.enumerable = descriptor.enumerable || false;
|
|
72
|
+
descriptor.configurable = true;
|
|
73
|
+
if ("value" in descriptor) descriptor.writable = true;
|
|
74
|
+
Object.defineProperty(target, descriptor.key, descriptor);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function _create_class(Constructor, protoProps, staticProps) {
|
|
78
|
+
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
79
|
+
return Constructor;
|
|
80
|
+
}
|
|
81
|
+
function _define_property(obj, key, value) {
|
|
82
|
+
if (key in obj) {
|
|
83
|
+
Object.defineProperty(obj, key, {
|
|
84
|
+
value: value,
|
|
85
|
+
enumerable: true,
|
|
86
|
+
configurable: true,
|
|
87
|
+
writable: true
|
|
88
|
+
});
|
|
89
|
+
} else {
|
|
90
|
+
obj[key] = value;
|
|
91
|
+
}
|
|
92
|
+
return obj;
|
|
93
|
+
}
|
|
94
|
+
function _ts_generator(thisArg, body) {
|
|
95
|
+
var f, y, t, _ = {
|
|
96
|
+
label: 0,
|
|
97
|
+
sent: function() {
|
|
98
|
+
if (t[0] & 1) throw t[1];
|
|
99
|
+
return t[1];
|
|
100
|
+
},
|
|
101
|
+
trys: [],
|
|
102
|
+
ops: []
|
|
103
|
+
}, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
|
|
104
|
+
return d(g, "next", {
|
|
105
|
+
value: verb(0)
|
|
106
|
+
}), d(g, "throw", {
|
|
107
|
+
value: verb(1)
|
|
108
|
+
}), d(g, "return", {
|
|
109
|
+
value: verb(2)
|
|
110
|
+
}), typeof Symbol === "function" && d(g, Symbol.iterator, {
|
|
111
|
+
value: function() {
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
}), g;
|
|
115
|
+
function verb(n) {
|
|
116
|
+
return function(v) {
|
|
117
|
+
return step([
|
|
118
|
+
n,
|
|
119
|
+
v
|
|
120
|
+
]);
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function step(op) {
|
|
124
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
125
|
+
while(g && (g = 0, op[0] && (_ = 0)), _)try {
|
|
126
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
127
|
+
if (y = 0, t) op = [
|
|
128
|
+
op[0] & 2,
|
|
129
|
+
t.value
|
|
130
|
+
];
|
|
131
|
+
switch(op[0]){
|
|
132
|
+
case 0:
|
|
133
|
+
case 1:
|
|
134
|
+
t = op;
|
|
135
|
+
break;
|
|
136
|
+
case 4:
|
|
137
|
+
_.label++;
|
|
138
|
+
return {
|
|
139
|
+
value: op[1],
|
|
140
|
+
done: false
|
|
141
|
+
};
|
|
142
|
+
case 5:
|
|
143
|
+
_.label++;
|
|
144
|
+
y = op[1];
|
|
145
|
+
op = [
|
|
146
|
+
0
|
|
147
|
+
];
|
|
148
|
+
continue;
|
|
149
|
+
case 7:
|
|
150
|
+
op = _.ops.pop();
|
|
151
|
+
_.trys.pop();
|
|
152
|
+
continue;
|
|
153
|
+
default:
|
|
154
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
155
|
+
_ = 0;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
|
|
159
|
+
_.label = op[1];
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
if (op[0] === 6 && _.label < t[1]) {
|
|
163
|
+
_.label = t[1];
|
|
164
|
+
t = op;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
if (t && _.label < t[2]) {
|
|
168
|
+
_.label = t[2];
|
|
169
|
+
_.ops.push(op);
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
if (t[2]) _.ops.pop();
|
|
173
|
+
_.trys.pop();
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
op = body.call(thisArg, _);
|
|
177
|
+
} catch (e) {
|
|
178
|
+
op = [
|
|
179
|
+
6,
|
|
180
|
+
e
|
|
181
|
+
];
|
|
182
|
+
y = 0;
|
|
183
|
+
} finally{
|
|
184
|
+
f = t = 0;
|
|
185
|
+
}
|
|
186
|
+
if (op[0] & 5) throw op[1];
|
|
187
|
+
return {
|
|
188
|
+
value: op[0] ? op[1] : void 0,
|
|
189
|
+
done: true
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
36
193
|
/**
|
|
37
194
|
* Used for loading services in the browser that are imported from other scripts, such as Facebook, Segment, Stripe, etc.
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
195
|
+
*/ var AbstractAsyncWindowLoadedService = /*#__PURE__*/ function() {
|
|
196
|
+
function AbstractAsyncWindowLoadedService(windowKey, callbackKey, serviceName, preload) {
|
|
197
|
+
var _this = this;
|
|
198
|
+
_class_call_check(this, AbstractAsyncWindowLoadedService);
|
|
199
|
+
_define_property(this, "_loading", new rxjs.BehaviorSubject(undefined));
|
|
200
|
+
/**
|
|
42
201
|
* Key that is attached to the window for the object that is the service when finished loading.
|
|
43
|
-
*/
|
|
44
|
-
|
|
45
|
-
/**
|
|
202
|
+
*/ _define_property(this, "_windowKey", void 0);
|
|
203
|
+
/**
|
|
46
204
|
* Optional key attached to window that is a function that is executed when the setup is complete.
|
|
47
|
-
*/
|
|
48
|
-
|
|
49
|
-
/**
|
|
205
|
+
*/ _define_property(this, "_callbackKey", void 0);
|
|
206
|
+
/**
|
|
50
207
|
* Service name used in logging. Defaults to the windowKey.
|
|
51
|
-
*/
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
208
|
+
*/ _define_property(this, "_serviceName", void 0);
|
|
209
|
+
/**
|
|
210
|
+
* Observable that emits the loading promise. Subscribing triggers the initial load if not already started.
|
|
211
|
+
*/ _define_property(this, "loading$", this._loading.pipe(rxjs$1.tapFirst(function() {
|
|
212
|
+
return _this.loadService();
|
|
213
|
+
}), rxjs$1.filterMaybe(), rxjs.shareReplay(1)));
|
|
214
|
+
/**
|
|
215
|
+
* Observable that emits the resolved service instance once loading completes. Replays the last value to new subscribers.
|
|
216
|
+
*/ _define_property(this, "service$", this.loading$.pipe(rxjs.switchMap(function(x) {
|
|
217
|
+
return rxjs.from(x);
|
|
218
|
+
}), rxjs.shareReplay(1)));
|
|
60
219
|
this._windowKey = windowKey;
|
|
61
220
|
this._callbackKey = callbackKey;
|
|
62
|
-
this._serviceName = serviceName
|
|
221
|
+
this._serviceName = serviceName !== null && serviceName !== void 0 ? serviceName : windowKey;
|
|
63
222
|
if (util.stringToBoolean(preload)) {
|
|
64
223
|
// Begin loading the service immediately.
|
|
65
|
-
setTimeout(()
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
destroy() {
|
|
69
|
-
this._loading.complete();
|
|
70
|
-
}
|
|
71
|
-
getService() {
|
|
72
|
-
return rxjs.firstValueFrom(this.service$);
|
|
73
|
-
}
|
|
74
|
-
// MARK: Loading
|
|
75
|
-
loadService() {
|
|
76
|
-
if (!this._loading.value) {
|
|
77
|
-
const loadingPromise = new Promise((resolve, reject) => {
|
|
78
|
-
let loadTry = 0;
|
|
79
|
-
const rejectWithError = () => {
|
|
80
|
-
reject(new Error(`Service "${this._serviceName}" failed loading with windowKey "${this._windowKey}"`));
|
|
81
|
-
};
|
|
82
|
-
const tryLoad = () => {
|
|
83
|
-
const windowRef = window;
|
|
84
|
-
// Loaded before the promise.
|
|
85
|
-
if (windowRef[this._windowKey]) {
|
|
86
|
-
// Not yet finished loading async. Intercept the function.
|
|
87
|
-
// console.log('Window key.');
|
|
88
|
-
return resolve(this.completeLoadingService());
|
|
89
|
-
}
|
|
90
|
-
else if (this._callbackKey && windowRef[this._callbackKey]) {
|
|
91
|
-
// console.log('Callback key.');
|
|
92
|
-
windowRef[this._callbackKey] = () => resolve(this.completeLoadingService());
|
|
93
|
-
}
|
|
94
|
-
else if (loadTry < 10) {
|
|
95
|
-
loadTry += 1;
|
|
96
|
-
// console.log('Try reload...');
|
|
97
|
-
setTimeout(() => tryLoad(), 1000);
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
const retry = this._onLoadServiceFailure();
|
|
101
|
-
if (retry) {
|
|
102
|
-
retry.then((x) => resolve(x)).catch(() => rejectWithError());
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
rejectWithError();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
tryLoad();
|
|
224
|
+
setTimeout(function() {
|
|
225
|
+
return _this.loadService().catch();
|
|
110
226
|
});
|
|
111
|
-
this._loading.next(loadingPromise);
|
|
112
227
|
}
|
|
113
|
-
return this._loading.value;
|
|
114
228
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
229
|
+
_create_class(AbstractAsyncWindowLoadedService, [
|
|
230
|
+
{
|
|
231
|
+
/**
|
|
232
|
+
* Completes the internal loading subject, stopping any pending service resolution.
|
|
233
|
+
*/ key: "destroy",
|
|
234
|
+
value: function destroy() {
|
|
235
|
+
this._loading.complete();
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
/**
|
|
240
|
+
* Returns a promise that resolves with the loaded service instance.
|
|
241
|
+
*
|
|
242
|
+
* Triggers loading if not already started.
|
|
243
|
+
*/ key: "getService",
|
|
244
|
+
value: function getService() {
|
|
245
|
+
return rxjs.firstValueFrom(this.service$);
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
// MARK: Loading
|
|
250
|
+
/**
|
|
251
|
+
* Initiates the service loading process by polling the `window` object for the service key.
|
|
252
|
+
*
|
|
253
|
+
* Retries up to 10 times at 1-second intervals before invoking `_onLoadServiceFailure()`.
|
|
254
|
+
* Subsequent calls return the same promise without re-initiating.
|
|
255
|
+
*
|
|
256
|
+
* @returns Promise that resolves with the loaded service
|
|
257
|
+
*/ key: "loadService",
|
|
258
|
+
value: function loadService() {
|
|
259
|
+
var _this = this;
|
|
260
|
+
if (!this._loading.value) {
|
|
261
|
+
var loadingPromise = new Promise(function(resolve, reject) {
|
|
262
|
+
var loadTry = 0;
|
|
263
|
+
var rejectWithError = function rejectWithError() {
|
|
264
|
+
reject(new Error('Service "'.concat(_this._serviceName, '" failed loading with windowKey "').concat(_this._windowKey, '"')));
|
|
265
|
+
};
|
|
266
|
+
var tryLoad = function tryLoad1() {
|
|
267
|
+
var windowRef = window;
|
|
268
|
+
// Loaded before the promise.
|
|
269
|
+
if (windowRef[_this._windowKey]) {
|
|
270
|
+
// Not yet finished loading async. Intercept the function.
|
|
271
|
+
// console.log('Window key.');
|
|
272
|
+
return resolve(_this.completeLoadingService());
|
|
273
|
+
} else if (_this._callbackKey && windowRef[_this._callbackKey]) {
|
|
274
|
+
// console.log('Callback key.');
|
|
275
|
+
windowRef[_this._callbackKey] = function() {
|
|
276
|
+
return resolve(_this.completeLoadingService());
|
|
277
|
+
};
|
|
278
|
+
} else if (loadTry < 10) {
|
|
279
|
+
loadTry += 1;
|
|
280
|
+
// console.log('Try reload...');
|
|
281
|
+
setTimeout(function() {
|
|
282
|
+
return tryLoad();
|
|
283
|
+
}, 1000);
|
|
284
|
+
} else {
|
|
285
|
+
var retry = _this._onLoadServiceFailure();
|
|
286
|
+
if (retry) {
|
|
287
|
+
retry.then(function(x) {
|
|
288
|
+
return resolve(x);
|
|
289
|
+
}).catch(function() {
|
|
290
|
+
return rejectWithError();
|
|
291
|
+
});
|
|
292
|
+
} else {
|
|
293
|
+
rejectWithError();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
tryLoad();
|
|
298
|
+
});
|
|
299
|
+
this._loading.next(loadingPromise);
|
|
300
|
+
}
|
|
301
|
+
return this._loading.value;
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
/**
|
|
306
|
+
* Hook called when the service fails to load after all retry attempts.
|
|
307
|
+
*
|
|
308
|
+
* Subclasses can override to attempt an alternative loading strategy or return a fallback promise.
|
|
309
|
+
*
|
|
310
|
+
* @returns A promise resolving with the service if recovery succeeds, or `void` to reject
|
|
311
|
+
*/ key: "_onLoadServiceFailure",
|
|
312
|
+
value: function _onLoadServiceFailure() {
|
|
313
|
+
// override in parent if needed.
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
key: "completeLoadingService",
|
|
318
|
+
value: function completeLoadingService() {
|
|
319
|
+
return _async_to_generator(function() {
|
|
320
|
+
var service, initializedService;
|
|
321
|
+
return _ts_generator(this, function(_state) {
|
|
322
|
+
switch(_state.label){
|
|
323
|
+
case 0:
|
|
324
|
+
return [
|
|
325
|
+
4,
|
|
326
|
+
this._prepareCompleteLoadingService()
|
|
327
|
+
];
|
|
328
|
+
case 1:
|
|
329
|
+
_state.sent();
|
|
330
|
+
service = window[this._windowKey];
|
|
331
|
+
if (!service) {
|
|
332
|
+
throw new Error('Service "'.concat(this._serviceName, '" could not complete loading.'));
|
|
333
|
+
}
|
|
334
|
+
return [
|
|
335
|
+
4,
|
|
336
|
+
this._initService(service)
|
|
337
|
+
];
|
|
338
|
+
case 2:
|
|
339
|
+
initializedService = _state.sent();
|
|
340
|
+
return [
|
|
341
|
+
2,
|
|
342
|
+
initializedService !== null && initializedService !== void 0 ? initializedService : service
|
|
343
|
+
];
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
}).call(this);
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
/**
|
|
351
|
+
* Hook called before completing the service load. Subclasses can override to perform
|
|
352
|
+
* additional async setup before the service reference is read from `window`.
|
|
353
|
+
*/ key: "_prepareCompleteLoadingService",
|
|
354
|
+
value: function _prepareCompleteLoadingService() {
|
|
355
|
+
return Promise.resolve();
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
/**
|
|
360
|
+
* Hook called after the service is retrieved from `window` to perform initialization.
|
|
361
|
+
*
|
|
362
|
+
* Subclasses can override to configure or wrap the service before it is emitted to subscribers.
|
|
363
|
+
*
|
|
364
|
+
* @param service - The raw service instance from the window
|
|
365
|
+
* @returns The initialized service, or void to use the original
|
|
366
|
+
*/ key: "_initService",
|
|
367
|
+
value: function _initService(service) {
|
|
368
|
+
return Promise.resolve(service);
|
|
369
|
+
}
|
|
123
370
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
_prepareCompleteLoadingService() {
|
|
129
|
-
return Promise.resolve();
|
|
130
|
-
}
|
|
131
|
-
_initService(service) {
|
|
132
|
-
return Promise.resolve(service);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
371
|
+
]);
|
|
372
|
+
return AbstractAsyncWindowLoadedService;
|
|
373
|
+
}
|
|
374
|
+
();
|
|
135
375
|
|
|
136
376
|
// https://dev.to/maciejtrzcinski/100vh-problem-with-ios-safari-3ge9
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
377
|
+
/**
|
|
378
|
+
* Default CSS custom property name used to store the viewport height value.
|
|
379
|
+
*/ var DEFAULT_VH100_VARIABLE_NAME = 'vh100';
|
|
380
|
+
/**
|
|
381
|
+
* Creates a function that sets a CSS custom property on `document.documentElement` to the current `window.innerHeight` in pixels.
|
|
382
|
+
*
|
|
383
|
+
* This is a workaround for the iOS Safari 100vh bug where `100vh` includes the browser chrome,
|
|
384
|
+
* causing layout overflow. The returned function can be called to refresh the property value.
|
|
385
|
+
*
|
|
386
|
+
* @param cssVariableName - Name of the CSS custom property (without the `--` prefix)
|
|
387
|
+
* @returns A zero-argument function that updates the CSS property to the current inner height
|
|
388
|
+
*
|
|
389
|
+
* @example
|
|
390
|
+
* ```typescript
|
|
391
|
+
* const refresh = refreshVh100Function('vh100');
|
|
392
|
+
* refresh(); // sets --vh100 to e.g. "812px"
|
|
393
|
+
* ```
|
|
394
|
+
*/ function refreshVh100Function() {
|
|
395
|
+
var cssVariableName = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : DEFAULT_VH100_VARIABLE_NAME;
|
|
396
|
+
var cssProperty = "--".concat(cssVariableName);
|
|
397
|
+
return function() {
|
|
398
|
+
var doc = document.documentElement;
|
|
399
|
+
doc.style.setProperty(cssProperty, "".concat(window.innerHeight, "px"));
|
|
143
400
|
};
|
|
144
401
|
}
|
|
145
402
|
/**
|
|
146
403
|
* Adds window event listeners to populate the css variable `vh100`, or another input variable name, with the current window height.
|
|
147
|
-
*/
|
|
148
|
-
|
|
149
|
-
const refreshPropertyValue = refreshVh100Function(cssVariableName);
|
|
404
|
+
*/ function watchWindowAndUpdateVh100StyleProperty(cssVariableName) {
|
|
405
|
+
var refreshPropertyValue = refreshVh100Function(cssVariableName);
|
|
150
406
|
window.addEventListener('resize', refreshPropertyValue);
|
|
151
407
|
window.addEventListener('orientationchange', refreshPropertyValue);
|
|
152
408
|
refreshPropertyValue();
|
|
@@ -155,18 +411,50 @@ function watchWindowAndUpdateVh100StyleProperty(cssVariableName) {
|
|
|
155
411
|
// MARK: Window Location Utiltiies
|
|
156
412
|
/**
|
|
157
413
|
* Whether or not the current host is localhost. Useful for determining local dev environments.
|
|
158
|
-
*/
|
|
159
|
-
function isLocalhost() {
|
|
414
|
+
*/ function isLocalhost() {
|
|
160
415
|
return window.location.hostname === 'localhost';
|
|
161
416
|
}
|
|
162
|
-
|
|
163
|
-
|
|
417
|
+
/**
|
|
418
|
+
* Constructs a full URL by combining the current window's base URL with the given relative path.
|
|
419
|
+
*
|
|
420
|
+
* @param path - Relative path to append to the base URL
|
|
421
|
+
* @returns Full URL string
|
|
422
|
+
*
|
|
423
|
+
* @example
|
|
424
|
+
* ```typescript
|
|
425
|
+
* // On https://example.com:3000
|
|
426
|
+
* const url = makeWindowPath('/api/users'); // "https://example.com:3000/api/users"
|
|
427
|
+
* ```
|
|
428
|
+
*/ function makeWindowPath(path) {
|
|
429
|
+
return "".concat(getBaseWindowUrl()).concat(path);
|
|
164
430
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
431
|
+
/**
|
|
432
|
+
* Returns the base URL of the current window, including protocol, hostname, and port (if present).
|
|
433
|
+
*
|
|
434
|
+
* @returns Base URL string without trailing slash
|
|
435
|
+
*
|
|
436
|
+
* @example
|
|
437
|
+
* ```typescript
|
|
438
|
+
* // On https://example.com:8080/some/path
|
|
439
|
+
* const base = getBaseWindowUrl(); // "https://example.com:8080"
|
|
440
|
+
* ```
|
|
441
|
+
*/ function getBaseWindowUrl() {
|
|
442
|
+
var port = window.location.port ? ':' + window.location.port : '';
|
|
443
|
+
return "".concat(window.location.protocol, "//").concat(window.location.hostname).concat(port);
|
|
168
444
|
}
|
|
169
|
-
|
|
445
|
+
/**
|
|
446
|
+
* Returns the current window pathname concatenated with the query string.
|
|
447
|
+
*
|
|
448
|
+
* Useful for capturing the full relative URL for redirect-after-login or deep linking scenarios.
|
|
449
|
+
*
|
|
450
|
+
* @returns Pathname and query string (e.g. "/app/dashboard?tab=settings")
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* ```typescript
|
|
454
|
+
* // On https://example.com/app/dashboard?tab=settings
|
|
455
|
+
* const path = getWindowPathNameWithQuery(); // "/app/dashboard?tab=settings"
|
|
456
|
+
* ```
|
|
457
|
+
*/ function getWindowPathNameWithQuery() {
|
|
170
458
|
return window.location.pathname + window.location.search;
|
|
171
459
|
}
|
|
172
460
|
|
package/index.esm.js
CHANGED
|
@@ -4,13 +4,11 @@ import { BehaviorSubject, shareReplay, switchMap, from, firstValueFrom } from 'r
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Creatse a new BrowserObjectURLRef.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
let browserUrl;
|
|
7
|
+
*/ function browserObjectUrlRef() {
|
|
8
|
+
var browserUrl;
|
|
10
9
|
/**
|
|
11
10
|
* Revokes the existing browser object URL, if one exists.
|
|
12
|
-
*/
|
|
13
|
-
function destroy() {
|
|
11
|
+
*/ function destroy() {
|
|
14
12
|
if (browserUrl) {
|
|
15
13
|
URL.revokeObjectURL(browserUrl);
|
|
16
14
|
}
|
|
@@ -23,128 +21,386 @@ function browserObjectUrlRef() {
|
|
|
23
21
|
return browserUrl;
|
|
24
22
|
}
|
|
25
23
|
return {
|
|
26
|
-
destroy,
|
|
27
|
-
getBrowserUrl: ()
|
|
24
|
+
destroy: destroy,
|
|
25
|
+
getBrowserUrl: function getBrowserUrl() {
|
|
26
|
+
return browserUrl;
|
|
27
|
+
},
|
|
28
28
|
createBrowserUrl: createBrowserUrl
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
33
|
+
try {
|
|
34
|
+
var info = gen[key](arg);
|
|
35
|
+
var value = info.value;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
reject(error);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (info.done) {
|
|
41
|
+
resolve(value);
|
|
42
|
+
} else {
|
|
43
|
+
Promise.resolve(value).then(_next, _throw);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function _async_to_generator(fn) {
|
|
47
|
+
return function() {
|
|
48
|
+
var self = this, args = arguments;
|
|
49
|
+
return new Promise(function(resolve, reject) {
|
|
50
|
+
var gen = fn.apply(self, args);
|
|
51
|
+
function _next(value) {
|
|
52
|
+
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
|
|
53
|
+
}
|
|
54
|
+
function _throw(err) {
|
|
55
|
+
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
|
|
56
|
+
}
|
|
57
|
+
_next(undefined);
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function _class_call_check(instance, Constructor) {
|
|
62
|
+
if (!(instance instanceof Constructor)) {
|
|
63
|
+
throw new TypeError("Cannot call a class as a function");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function _defineProperties(target, props) {
|
|
67
|
+
for(var i = 0; i < props.length; i++){
|
|
68
|
+
var descriptor = props[i];
|
|
69
|
+
descriptor.enumerable = descriptor.enumerable || false;
|
|
70
|
+
descriptor.configurable = true;
|
|
71
|
+
if ("value" in descriptor) descriptor.writable = true;
|
|
72
|
+
Object.defineProperty(target, descriptor.key, descriptor);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function _create_class(Constructor, protoProps, staticProps) {
|
|
76
|
+
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
77
|
+
return Constructor;
|
|
78
|
+
}
|
|
79
|
+
function _define_property(obj, key, value) {
|
|
80
|
+
if (key in obj) {
|
|
81
|
+
Object.defineProperty(obj, key, {
|
|
82
|
+
value: value,
|
|
83
|
+
enumerable: true,
|
|
84
|
+
configurable: true,
|
|
85
|
+
writable: true
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
obj[key] = value;
|
|
89
|
+
}
|
|
90
|
+
return obj;
|
|
91
|
+
}
|
|
92
|
+
function _ts_generator(thisArg, body) {
|
|
93
|
+
var f, y, t, _ = {
|
|
94
|
+
label: 0,
|
|
95
|
+
sent: function() {
|
|
96
|
+
if (t[0] & 1) throw t[1];
|
|
97
|
+
return t[1];
|
|
98
|
+
},
|
|
99
|
+
trys: [],
|
|
100
|
+
ops: []
|
|
101
|
+
}, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
|
|
102
|
+
return d(g, "next", {
|
|
103
|
+
value: verb(0)
|
|
104
|
+
}), d(g, "throw", {
|
|
105
|
+
value: verb(1)
|
|
106
|
+
}), d(g, "return", {
|
|
107
|
+
value: verb(2)
|
|
108
|
+
}), typeof Symbol === "function" && d(g, Symbol.iterator, {
|
|
109
|
+
value: function() {
|
|
110
|
+
return this;
|
|
111
|
+
}
|
|
112
|
+
}), g;
|
|
113
|
+
function verb(n) {
|
|
114
|
+
return function(v) {
|
|
115
|
+
return step([
|
|
116
|
+
n,
|
|
117
|
+
v
|
|
118
|
+
]);
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function step(op) {
|
|
122
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
123
|
+
while(g && (g = 0, op[0] && (_ = 0)), _)try {
|
|
124
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
125
|
+
if (y = 0, t) op = [
|
|
126
|
+
op[0] & 2,
|
|
127
|
+
t.value
|
|
128
|
+
];
|
|
129
|
+
switch(op[0]){
|
|
130
|
+
case 0:
|
|
131
|
+
case 1:
|
|
132
|
+
t = op;
|
|
133
|
+
break;
|
|
134
|
+
case 4:
|
|
135
|
+
_.label++;
|
|
136
|
+
return {
|
|
137
|
+
value: op[1],
|
|
138
|
+
done: false
|
|
139
|
+
};
|
|
140
|
+
case 5:
|
|
141
|
+
_.label++;
|
|
142
|
+
y = op[1];
|
|
143
|
+
op = [
|
|
144
|
+
0
|
|
145
|
+
];
|
|
146
|
+
continue;
|
|
147
|
+
case 7:
|
|
148
|
+
op = _.ops.pop();
|
|
149
|
+
_.trys.pop();
|
|
150
|
+
continue;
|
|
151
|
+
default:
|
|
152
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
153
|
+
_ = 0;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
|
|
157
|
+
_.label = op[1];
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
if (op[0] === 6 && _.label < t[1]) {
|
|
161
|
+
_.label = t[1];
|
|
162
|
+
t = op;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
if (t && _.label < t[2]) {
|
|
166
|
+
_.label = t[2];
|
|
167
|
+
_.ops.push(op);
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
if (t[2]) _.ops.pop();
|
|
171
|
+
_.trys.pop();
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
op = body.call(thisArg, _);
|
|
175
|
+
} catch (e) {
|
|
176
|
+
op = [
|
|
177
|
+
6,
|
|
178
|
+
e
|
|
179
|
+
];
|
|
180
|
+
y = 0;
|
|
181
|
+
} finally{
|
|
182
|
+
f = t = 0;
|
|
183
|
+
}
|
|
184
|
+
if (op[0] & 5) throw op[1];
|
|
185
|
+
return {
|
|
186
|
+
value: op[0] ? op[1] : void 0,
|
|
187
|
+
done: true
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
34
191
|
/**
|
|
35
192
|
* Used for loading services in the browser that are imported from other scripts, such as Facebook, Segment, Stripe, etc.
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
193
|
+
*/ var AbstractAsyncWindowLoadedService = /*#__PURE__*/ function() {
|
|
194
|
+
function AbstractAsyncWindowLoadedService(windowKey, callbackKey, serviceName, preload) {
|
|
195
|
+
var _this = this;
|
|
196
|
+
_class_call_check(this, AbstractAsyncWindowLoadedService);
|
|
197
|
+
_define_property(this, "_loading", new BehaviorSubject(undefined));
|
|
198
|
+
/**
|
|
40
199
|
* Key that is attached to the window for the object that is the service when finished loading.
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
/**
|
|
200
|
+
*/ _define_property(this, "_windowKey", void 0);
|
|
201
|
+
/**
|
|
44
202
|
* Optional key attached to window that is a function that is executed when the setup is complete.
|
|
45
|
-
*/
|
|
46
|
-
|
|
47
|
-
/**
|
|
203
|
+
*/ _define_property(this, "_callbackKey", void 0);
|
|
204
|
+
/**
|
|
48
205
|
* Service name used in logging. Defaults to the windowKey.
|
|
49
|
-
*/
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
206
|
+
*/ _define_property(this, "_serviceName", void 0);
|
|
207
|
+
/**
|
|
208
|
+
* Observable that emits the loading promise. Subscribing triggers the initial load if not already started.
|
|
209
|
+
*/ _define_property(this, "loading$", this._loading.pipe(tapFirst(function() {
|
|
210
|
+
return _this.loadService();
|
|
211
|
+
}), filterMaybe(), shareReplay(1)));
|
|
212
|
+
/**
|
|
213
|
+
* Observable that emits the resolved service instance once loading completes. Replays the last value to new subscribers.
|
|
214
|
+
*/ _define_property(this, "service$", this.loading$.pipe(switchMap(function(x) {
|
|
215
|
+
return from(x);
|
|
216
|
+
}), shareReplay(1)));
|
|
58
217
|
this._windowKey = windowKey;
|
|
59
218
|
this._callbackKey = callbackKey;
|
|
60
|
-
this._serviceName = serviceName
|
|
219
|
+
this._serviceName = serviceName !== null && serviceName !== void 0 ? serviceName : windowKey;
|
|
61
220
|
if (stringToBoolean(preload)) {
|
|
62
221
|
// Begin loading the service immediately.
|
|
63
|
-
setTimeout(()
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
destroy() {
|
|
67
|
-
this._loading.complete();
|
|
68
|
-
}
|
|
69
|
-
getService() {
|
|
70
|
-
return firstValueFrom(this.service$);
|
|
71
|
-
}
|
|
72
|
-
// MARK: Loading
|
|
73
|
-
loadService() {
|
|
74
|
-
if (!this._loading.value) {
|
|
75
|
-
const loadingPromise = new Promise((resolve, reject) => {
|
|
76
|
-
let loadTry = 0;
|
|
77
|
-
const rejectWithError = () => {
|
|
78
|
-
reject(new Error(`Service "${this._serviceName}" failed loading with windowKey "${this._windowKey}"`));
|
|
79
|
-
};
|
|
80
|
-
const tryLoad = () => {
|
|
81
|
-
const windowRef = window;
|
|
82
|
-
// Loaded before the promise.
|
|
83
|
-
if (windowRef[this._windowKey]) {
|
|
84
|
-
// Not yet finished loading async. Intercept the function.
|
|
85
|
-
// console.log('Window key.');
|
|
86
|
-
return resolve(this.completeLoadingService());
|
|
87
|
-
}
|
|
88
|
-
else if (this._callbackKey && windowRef[this._callbackKey]) {
|
|
89
|
-
// console.log('Callback key.');
|
|
90
|
-
windowRef[this._callbackKey] = () => resolve(this.completeLoadingService());
|
|
91
|
-
}
|
|
92
|
-
else if (loadTry < 10) {
|
|
93
|
-
loadTry += 1;
|
|
94
|
-
// console.log('Try reload...');
|
|
95
|
-
setTimeout(() => tryLoad(), 1000);
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
const retry = this._onLoadServiceFailure();
|
|
99
|
-
if (retry) {
|
|
100
|
-
retry.then((x) => resolve(x)).catch(() => rejectWithError());
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
rejectWithError();
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
tryLoad();
|
|
222
|
+
setTimeout(function() {
|
|
223
|
+
return _this.loadService().catch();
|
|
108
224
|
});
|
|
109
|
-
this._loading.next(loadingPromise);
|
|
110
225
|
}
|
|
111
|
-
return this._loading.value;
|
|
112
226
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
227
|
+
_create_class(AbstractAsyncWindowLoadedService, [
|
|
228
|
+
{
|
|
229
|
+
/**
|
|
230
|
+
* Completes the internal loading subject, stopping any pending service resolution.
|
|
231
|
+
*/ key: "destroy",
|
|
232
|
+
value: function destroy() {
|
|
233
|
+
this._loading.complete();
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
/**
|
|
238
|
+
* Returns a promise that resolves with the loaded service instance.
|
|
239
|
+
*
|
|
240
|
+
* Triggers loading if not already started.
|
|
241
|
+
*/ key: "getService",
|
|
242
|
+
value: function getService() {
|
|
243
|
+
return firstValueFrom(this.service$);
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
// MARK: Loading
|
|
248
|
+
/**
|
|
249
|
+
* Initiates the service loading process by polling the `window` object for the service key.
|
|
250
|
+
*
|
|
251
|
+
* Retries up to 10 times at 1-second intervals before invoking `_onLoadServiceFailure()`.
|
|
252
|
+
* Subsequent calls return the same promise without re-initiating.
|
|
253
|
+
*
|
|
254
|
+
* @returns Promise that resolves with the loaded service
|
|
255
|
+
*/ key: "loadService",
|
|
256
|
+
value: function loadService() {
|
|
257
|
+
var _this = this;
|
|
258
|
+
if (!this._loading.value) {
|
|
259
|
+
var loadingPromise = new Promise(function(resolve, reject) {
|
|
260
|
+
var loadTry = 0;
|
|
261
|
+
var rejectWithError = function rejectWithError() {
|
|
262
|
+
reject(new Error('Service "'.concat(_this._serviceName, '" failed loading with windowKey "').concat(_this._windowKey, '"')));
|
|
263
|
+
};
|
|
264
|
+
var tryLoad = function tryLoad1() {
|
|
265
|
+
var windowRef = window;
|
|
266
|
+
// Loaded before the promise.
|
|
267
|
+
if (windowRef[_this._windowKey]) {
|
|
268
|
+
// Not yet finished loading async. Intercept the function.
|
|
269
|
+
// console.log('Window key.');
|
|
270
|
+
return resolve(_this.completeLoadingService());
|
|
271
|
+
} else if (_this._callbackKey && windowRef[_this._callbackKey]) {
|
|
272
|
+
// console.log('Callback key.');
|
|
273
|
+
windowRef[_this._callbackKey] = function() {
|
|
274
|
+
return resolve(_this.completeLoadingService());
|
|
275
|
+
};
|
|
276
|
+
} else if (loadTry < 10) {
|
|
277
|
+
loadTry += 1;
|
|
278
|
+
// console.log('Try reload...');
|
|
279
|
+
setTimeout(function() {
|
|
280
|
+
return tryLoad();
|
|
281
|
+
}, 1000);
|
|
282
|
+
} else {
|
|
283
|
+
var retry = _this._onLoadServiceFailure();
|
|
284
|
+
if (retry) {
|
|
285
|
+
retry.then(function(x) {
|
|
286
|
+
return resolve(x);
|
|
287
|
+
}).catch(function() {
|
|
288
|
+
return rejectWithError();
|
|
289
|
+
});
|
|
290
|
+
} else {
|
|
291
|
+
rejectWithError();
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
tryLoad();
|
|
296
|
+
});
|
|
297
|
+
this._loading.next(loadingPromise);
|
|
298
|
+
}
|
|
299
|
+
return this._loading.value;
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
/**
|
|
304
|
+
* Hook called when the service fails to load after all retry attempts.
|
|
305
|
+
*
|
|
306
|
+
* Subclasses can override to attempt an alternative loading strategy or return a fallback promise.
|
|
307
|
+
*
|
|
308
|
+
* @returns A promise resolving with the service if recovery succeeds, or `void` to reject
|
|
309
|
+
*/ key: "_onLoadServiceFailure",
|
|
310
|
+
value: function _onLoadServiceFailure() {
|
|
311
|
+
// override in parent if needed.
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
key: "completeLoadingService",
|
|
316
|
+
value: function completeLoadingService() {
|
|
317
|
+
return _async_to_generator(function() {
|
|
318
|
+
var service, initializedService;
|
|
319
|
+
return _ts_generator(this, function(_state) {
|
|
320
|
+
switch(_state.label){
|
|
321
|
+
case 0:
|
|
322
|
+
return [
|
|
323
|
+
4,
|
|
324
|
+
this._prepareCompleteLoadingService()
|
|
325
|
+
];
|
|
326
|
+
case 1:
|
|
327
|
+
_state.sent();
|
|
328
|
+
service = window[this._windowKey];
|
|
329
|
+
if (!service) {
|
|
330
|
+
throw new Error('Service "'.concat(this._serviceName, '" could not complete loading.'));
|
|
331
|
+
}
|
|
332
|
+
return [
|
|
333
|
+
4,
|
|
334
|
+
this._initService(service)
|
|
335
|
+
];
|
|
336
|
+
case 2:
|
|
337
|
+
initializedService = _state.sent();
|
|
338
|
+
return [
|
|
339
|
+
2,
|
|
340
|
+
initializedService !== null && initializedService !== void 0 ? initializedService : service
|
|
341
|
+
];
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}).call(this);
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
/**
|
|
349
|
+
* Hook called before completing the service load. Subclasses can override to perform
|
|
350
|
+
* additional async setup before the service reference is read from `window`.
|
|
351
|
+
*/ key: "_prepareCompleteLoadingService",
|
|
352
|
+
value: function _prepareCompleteLoadingService() {
|
|
353
|
+
return Promise.resolve();
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
/**
|
|
358
|
+
* Hook called after the service is retrieved from `window` to perform initialization.
|
|
359
|
+
*
|
|
360
|
+
* Subclasses can override to configure or wrap the service before it is emitted to subscribers.
|
|
361
|
+
*
|
|
362
|
+
* @param service - The raw service instance from the window
|
|
363
|
+
* @returns The initialized service, or void to use the original
|
|
364
|
+
*/ key: "_initService",
|
|
365
|
+
value: function _initService(service) {
|
|
366
|
+
return Promise.resolve(service);
|
|
367
|
+
}
|
|
121
368
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
_prepareCompleteLoadingService() {
|
|
127
|
-
return Promise.resolve();
|
|
128
|
-
}
|
|
129
|
-
_initService(service) {
|
|
130
|
-
return Promise.resolve(service);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
369
|
+
]);
|
|
370
|
+
return AbstractAsyncWindowLoadedService;
|
|
371
|
+
}
|
|
372
|
+
();
|
|
133
373
|
|
|
134
374
|
// https://dev.to/maciejtrzcinski/100vh-problem-with-ios-safari-3ge9
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
375
|
+
/**
|
|
376
|
+
* Default CSS custom property name used to store the viewport height value.
|
|
377
|
+
*/ var DEFAULT_VH100_VARIABLE_NAME = 'vh100';
|
|
378
|
+
/**
|
|
379
|
+
* Creates a function that sets a CSS custom property on `document.documentElement` to the current `window.innerHeight` in pixels.
|
|
380
|
+
*
|
|
381
|
+
* This is a workaround for the iOS Safari 100vh bug where `100vh` includes the browser chrome,
|
|
382
|
+
* causing layout overflow. The returned function can be called to refresh the property value.
|
|
383
|
+
*
|
|
384
|
+
* @param cssVariableName - Name of the CSS custom property (without the `--` prefix)
|
|
385
|
+
* @returns A zero-argument function that updates the CSS property to the current inner height
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* ```typescript
|
|
389
|
+
* const refresh = refreshVh100Function('vh100');
|
|
390
|
+
* refresh(); // sets --vh100 to e.g. "812px"
|
|
391
|
+
* ```
|
|
392
|
+
*/ function refreshVh100Function() {
|
|
393
|
+
var cssVariableName = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : DEFAULT_VH100_VARIABLE_NAME;
|
|
394
|
+
var cssProperty = "--".concat(cssVariableName);
|
|
395
|
+
return function() {
|
|
396
|
+
var doc = document.documentElement;
|
|
397
|
+
doc.style.setProperty(cssProperty, "".concat(window.innerHeight, "px"));
|
|
141
398
|
};
|
|
142
399
|
}
|
|
143
400
|
/**
|
|
144
401
|
* Adds window event listeners to populate the css variable `vh100`, or another input variable name, with the current window height.
|
|
145
|
-
*/
|
|
146
|
-
|
|
147
|
-
const refreshPropertyValue = refreshVh100Function(cssVariableName);
|
|
402
|
+
*/ function watchWindowAndUpdateVh100StyleProperty(cssVariableName) {
|
|
403
|
+
var refreshPropertyValue = refreshVh100Function(cssVariableName);
|
|
148
404
|
window.addEventListener('resize', refreshPropertyValue);
|
|
149
405
|
window.addEventListener('orientationchange', refreshPropertyValue);
|
|
150
406
|
refreshPropertyValue();
|
|
@@ -153,18 +409,50 @@ function watchWindowAndUpdateVh100StyleProperty(cssVariableName) {
|
|
|
153
409
|
// MARK: Window Location Utiltiies
|
|
154
410
|
/**
|
|
155
411
|
* Whether or not the current host is localhost. Useful for determining local dev environments.
|
|
156
|
-
*/
|
|
157
|
-
function isLocalhost() {
|
|
412
|
+
*/ function isLocalhost() {
|
|
158
413
|
return window.location.hostname === 'localhost';
|
|
159
414
|
}
|
|
160
|
-
|
|
161
|
-
|
|
415
|
+
/**
|
|
416
|
+
* Constructs a full URL by combining the current window's base URL with the given relative path.
|
|
417
|
+
*
|
|
418
|
+
* @param path - Relative path to append to the base URL
|
|
419
|
+
* @returns Full URL string
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* ```typescript
|
|
423
|
+
* // On https://example.com:3000
|
|
424
|
+
* const url = makeWindowPath('/api/users'); // "https://example.com:3000/api/users"
|
|
425
|
+
* ```
|
|
426
|
+
*/ function makeWindowPath(path) {
|
|
427
|
+
return "".concat(getBaseWindowUrl()).concat(path);
|
|
162
428
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
429
|
+
/**
|
|
430
|
+
* Returns the base URL of the current window, including protocol, hostname, and port (if present).
|
|
431
|
+
*
|
|
432
|
+
* @returns Base URL string without trailing slash
|
|
433
|
+
*
|
|
434
|
+
* @example
|
|
435
|
+
* ```typescript
|
|
436
|
+
* // On https://example.com:8080/some/path
|
|
437
|
+
* const base = getBaseWindowUrl(); // "https://example.com:8080"
|
|
438
|
+
* ```
|
|
439
|
+
*/ function getBaseWindowUrl() {
|
|
440
|
+
var port = window.location.port ? ':' + window.location.port : '';
|
|
441
|
+
return "".concat(window.location.protocol, "//").concat(window.location.hostname).concat(port);
|
|
166
442
|
}
|
|
167
|
-
|
|
443
|
+
/**
|
|
444
|
+
* Returns the current window pathname concatenated with the query string.
|
|
445
|
+
*
|
|
446
|
+
* Useful for capturing the full relative URL for redirect-after-login or deep linking scenarios.
|
|
447
|
+
*
|
|
448
|
+
* @returns Pathname and query string (e.g. "/app/dashboard?tab=settings")
|
|
449
|
+
*
|
|
450
|
+
* @example
|
|
451
|
+
* ```typescript
|
|
452
|
+
* // On https://example.com/app/dashboard?tab=settings
|
|
453
|
+
* const path = getWindowPathNameWithQuery(); // "/app/dashboard?tab=settings"
|
|
454
|
+
* ```
|
|
455
|
+
*/ function getWindowPathNameWithQuery() {
|
|
168
456
|
return window.location.pathname + window.location.search;
|
|
169
457
|
}
|
|
170
458
|
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/browser",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.3.1",
|
|
4
4
|
"peerDependencies": {
|
|
5
|
-
"@dereekb/util": "13.
|
|
6
|
-
"@dereekb/rxjs": "13.
|
|
5
|
+
"@dereekb/util": "13.3.1",
|
|
6
|
+
"@dereekb/rxjs": "13.3.1",
|
|
7
7
|
"rxjs": "^7.8.0"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {},
|
package/src/lib/service.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { type Maybe, type Destroyable } from '@dereekb/util';
|
|
2
2
|
import { type Observable } from 'rxjs';
|
|
3
|
+
/**
|
|
4
|
+
* Record type representing a service instance attached to the `window` object, keyed by a string identifier.
|
|
5
|
+
*/
|
|
3
6
|
export type ServiceInWindow<T> = Record<string, Maybe<T>>;
|
|
7
|
+
/**
|
|
8
|
+
* Record type representing a callback function attached to the `window` object, called when a service finishes loading.
|
|
9
|
+
*/
|
|
4
10
|
export type ServiceCallbackInWindow = Record<string, () => void>;
|
|
5
11
|
/**
|
|
6
12
|
* Used for loading services in the browser that are imported from other scripts, such as Facebook, Segment, Stripe, etc.
|
|
@@ -19,18 +25,61 @@ export declare abstract class AbstractAsyncWindowLoadedService<T> implements Des
|
|
|
19
25
|
* Service name used in logging. Defaults to the windowKey.
|
|
20
26
|
*/
|
|
21
27
|
private readonly _serviceName;
|
|
28
|
+
/**
|
|
29
|
+
* Observable that emits the loading promise. Subscribing triggers the initial load if not already started.
|
|
30
|
+
*/
|
|
22
31
|
readonly loading$: Observable<Promise<T>>;
|
|
32
|
+
/**
|
|
33
|
+
* Observable that emits the resolved service instance once loading completes. Replays the last value to new subscribers.
|
|
34
|
+
*/
|
|
23
35
|
readonly service$: Observable<T>;
|
|
24
36
|
/**
|
|
25
|
-
* @param windowKey
|
|
26
|
-
* @param callbackKey
|
|
37
|
+
* @param windowKey - Key on the `window` object where the loaded service is stored
|
|
38
|
+
* @param callbackKey - Optional key on `window` for a callback invoked when the service script finishes loading
|
|
39
|
+
* @param serviceName - Human-readable name for logging; defaults to `windowKey`
|
|
40
|
+
* @param preload - When truthy, begins loading the service immediately on construction
|
|
27
41
|
*/
|
|
28
42
|
constructor(windowKey: string, callbackKey?: string, serviceName?: Maybe<string>, preload?: Maybe<boolean | string>);
|
|
43
|
+
/**
|
|
44
|
+
* Completes the internal loading subject, stopping any pending service resolution.
|
|
45
|
+
*/
|
|
29
46
|
destroy(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Returns a promise that resolves with the loaded service instance.
|
|
49
|
+
*
|
|
50
|
+
* Triggers loading if not already started.
|
|
51
|
+
*/
|
|
30
52
|
getService(): Promise<T>;
|
|
53
|
+
/**
|
|
54
|
+
* Initiates the service loading process by polling the `window` object for the service key.
|
|
55
|
+
*
|
|
56
|
+
* Retries up to 10 times at 1-second intervals before invoking `_onLoadServiceFailure()`.
|
|
57
|
+
* Subsequent calls return the same promise without re-initiating.
|
|
58
|
+
*
|
|
59
|
+
* @returns Promise that resolves with the loaded service
|
|
60
|
+
*/
|
|
31
61
|
protected loadService(): Promise<T>;
|
|
62
|
+
/**
|
|
63
|
+
* Hook called when the service fails to load after all retry attempts.
|
|
64
|
+
*
|
|
65
|
+
* Subclasses can override to attempt an alternative loading strategy or return a fallback promise.
|
|
66
|
+
*
|
|
67
|
+
* @returns A promise resolving with the service if recovery succeeds, or `void` to reject
|
|
68
|
+
*/
|
|
32
69
|
protected _onLoadServiceFailure(): Promise<T> | void;
|
|
33
70
|
private completeLoadingService;
|
|
71
|
+
/**
|
|
72
|
+
* Hook called before completing the service load. Subclasses can override to perform
|
|
73
|
+
* additional async setup before the service reference is read from `window`.
|
|
74
|
+
*/
|
|
34
75
|
protected _prepareCompleteLoadingService(): Promise<unknown>;
|
|
76
|
+
/**
|
|
77
|
+
* Hook called after the service is retrieved from `window` to perform initialization.
|
|
78
|
+
*
|
|
79
|
+
* Subclasses can override to configure or wrap the service before it is emitted to subscribers.
|
|
80
|
+
*
|
|
81
|
+
* @param service - The raw service instance from the window
|
|
82
|
+
* @returns The initialized service, or void to use the original
|
|
83
|
+
*/
|
|
35
84
|
protected _initService(service: T): Promise<T | void>;
|
|
36
85
|
}
|
package/src/lib/vh100.d.ts
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default CSS custom property name used to store the viewport height value.
|
|
3
|
+
*/
|
|
1
4
|
export declare const DEFAULT_VH100_VARIABLE_NAME = "vh100";
|
|
5
|
+
/**
|
|
6
|
+
* Creates a function that sets a CSS custom property on `document.documentElement` to the current `window.innerHeight` in pixels.
|
|
7
|
+
*
|
|
8
|
+
* This is a workaround for the iOS Safari 100vh bug where `100vh` includes the browser chrome,
|
|
9
|
+
* causing layout overflow. The returned function can be called to refresh the property value.
|
|
10
|
+
*
|
|
11
|
+
* @param cssVariableName - Name of the CSS custom property (without the `--` prefix)
|
|
12
|
+
* @returns A zero-argument function that updates the CSS property to the current inner height
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const refresh = refreshVh100Function('vh100');
|
|
17
|
+
* refresh(); // sets --vh100 to e.g. "812px"
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
2
20
|
export declare function refreshVh100Function(cssVariableName?: string): () => void;
|
|
3
21
|
/**
|
|
4
22
|
* Adds window event listeners to populate the css variable `vh100`, or another input variable name, with the current window height.
|
package/src/lib/window.d.ts
CHANGED
|
@@ -2,6 +2,42 @@
|
|
|
2
2
|
* Whether or not the current host is localhost. Useful for determining local dev environments.
|
|
3
3
|
*/
|
|
4
4
|
export declare function isLocalhost(): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Constructs a full URL by combining the current window's base URL with the given relative path.
|
|
7
|
+
*
|
|
8
|
+
* @param path - Relative path to append to the base URL
|
|
9
|
+
* @returns Full URL string
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // On https://example.com:3000
|
|
14
|
+
* const url = makeWindowPath('/api/users'); // "https://example.com:3000/api/users"
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
5
17
|
export declare function makeWindowPath(path: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Returns the base URL of the current window, including protocol, hostname, and port (if present).
|
|
20
|
+
*
|
|
21
|
+
* @returns Base URL string without trailing slash
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // On https://example.com:8080/some/path
|
|
26
|
+
* const base = getBaseWindowUrl(); // "https://example.com:8080"
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
6
29
|
export declare function getBaseWindowUrl(): string;
|
|
30
|
+
/**
|
|
31
|
+
* Returns the current window pathname concatenated with the query string.
|
|
32
|
+
*
|
|
33
|
+
* Useful for capturing the full relative URL for redirect-after-login or deep linking scenarios.
|
|
34
|
+
*
|
|
35
|
+
* @returns Pathname and query string (e.g. "/app/dashboard?tab=settings")
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* // On https://example.com/app/dashboard?tab=settings
|
|
40
|
+
* const path = getWindowPathNameWithQuery(); // "/app/dashboard?tab=settings"
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
7
43
|
export declare function getWindowPathNameWithQuery(): string;
|