@authhero/widget 0.32.42 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authhero-widget/authhero-widget.esm.js +1 -1
- package/dist/authhero-widget/{p-5f7b7943.entry.js → p-5a319adc.entry.js} +1 -1
- package/dist/cjs/authhero-widget.cjs.entry.js +133 -35
- package/dist/collection/components/authhero-widget/authhero-widget.js +133 -35
- package/dist/components/authhero-widget.js +1 -1
- package/dist/esm/authhero-widget.entry.js +133 -35
- package/dist/types/components/authhero-widget/authhero-widget.d.ts +26 -0
- package/hydrate/index.js +133 -35
- package/hydrate/index.mjs +133 -35
- package/package.json +1 -1
package/hydrate/index.mjs
CHANGED
|
@@ -6956,6 +6956,94 @@ class AuthheroWidget {
|
|
|
6956
6956
|
}
|
|
6957
6957
|
});
|
|
6958
6958
|
}
|
|
6959
|
+
/**
|
|
6960
|
+
* Pending resolvers awaiting the next render, flushed by
|
|
6961
|
+
* `componentDidRender`. Lets `swapScreen` wait until the new screen is
|
|
6962
|
+
* actually in the DOM before measuring its height.
|
|
6963
|
+
*/
|
|
6964
|
+
pendingRenderResolvers = [];
|
|
6965
|
+
componentDidRender() {
|
|
6966
|
+
if (this.pendingRenderResolvers.length === 0)
|
|
6967
|
+
return;
|
|
6968
|
+
const resolvers = this.pendingRenderResolvers;
|
|
6969
|
+
this.pendingRenderResolvers = [];
|
|
6970
|
+
resolvers.forEach((resolve) => resolve());
|
|
6971
|
+
}
|
|
6972
|
+
/**
|
|
6973
|
+
* Resolves after Stencil flushes the next render, so `swapScreen` waits for
|
|
6974
|
+
* the new screen to be in the DOM before measuring its height.
|
|
6975
|
+
*/
|
|
6976
|
+
nextRender() {
|
|
6977
|
+
return new Promise((resolve) => {
|
|
6978
|
+
let settled = false;
|
|
6979
|
+
const done = () => {
|
|
6980
|
+
if (settled)
|
|
6981
|
+
return;
|
|
6982
|
+
settled = true;
|
|
6983
|
+
resolve();
|
|
6984
|
+
};
|
|
6985
|
+
this.pendingRenderResolvers.push(done);
|
|
6986
|
+
// Safety net: a screen swap always triggers a render here, but never
|
|
6987
|
+
// hang the swap if one somehow doesn't fire — resolve after a couple of
|
|
6988
|
+
// frames at the latest.
|
|
6989
|
+
requestAnimationFrame(() => requestAnimationFrame(done));
|
|
6990
|
+
});
|
|
6991
|
+
}
|
|
6992
|
+
/**
|
|
6993
|
+
* Apply a screen swap, animating the widget card's height to the next
|
|
6994
|
+
* screen's size (Stripe-style): lock the current height, swap the content,
|
|
6995
|
+
* measure the new natural height, then animate between them. The content
|
|
6996
|
+
* itself doesn't fade — the card just resizes.
|
|
6997
|
+
*
|
|
6998
|
+
* The card (.widget-container) is animated rather than the host because it
|
|
6999
|
+
* carries the background, so its resize is visible; clipping its content
|
|
7000
|
+
* (not the host) also keeps the card's drop-shadow intact.
|
|
7001
|
+
*
|
|
7002
|
+
* Degrades to an immediate swap when the Web Animations API is unavailable
|
|
7003
|
+
* or the user prefers reduced motion.
|
|
7004
|
+
*/
|
|
7005
|
+
async swapScreen(apply) {
|
|
7006
|
+
const card = this.el.shadowRoot?.querySelector(".widget-container");
|
|
7007
|
+
const prefersReducedMotion = typeof window.matchMedia === "function" &&
|
|
7008
|
+
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
7009
|
+
if (!card || typeof card.animate !== "function" || prefersReducedMotion) {
|
|
7010
|
+
apply();
|
|
7011
|
+
return;
|
|
7012
|
+
}
|
|
7013
|
+
// Lock the current height and clip, so swapping the content doesn't jump
|
|
7014
|
+
// before the animation runs.
|
|
7015
|
+
const startHeight = card.getBoundingClientRect().height;
|
|
7016
|
+
card.style.height = `${startHeight}px`;
|
|
7017
|
+
card.style.overflow = "hidden";
|
|
7018
|
+
apply();
|
|
7019
|
+
// Wait for the new screen to render before measuring its height.
|
|
7020
|
+
await this.nextRender();
|
|
7021
|
+
const cleanup = () => {
|
|
7022
|
+
card.style.height = "";
|
|
7023
|
+
card.style.overflow = "";
|
|
7024
|
+
};
|
|
7025
|
+
// Measure the new content's natural height without painting: toggle to
|
|
7026
|
+
// auto, read, restore — all synchronous, so there's no visible jump.
|
|
7027
|
+
card.style.height = "auto";
|
|
7028
|
+
const endHeight = card.getBoundingClientRect().height;
|
|
7029
|
+
card.style.height = `${startHeight}px`;
|
|
7030
|
+
card.getBoundingClientRect(); // force reflow from startHeight
|
|
7031
|
+
if (Math.abs(endHeight - startHeight) < 1) {
|
|
7032
|
+
cleanup();
|
|
7033
|
+
return;
|
|
7034
|
+
}
|
|
7035
|
+
const animation = card.animate([{ height: `${startHeight}px` }, { height: `${endHeight}px` }], { duration: 520, easing: "cubic-bezier(0.22, 1, 0.36, 1)" });
|
|
7036
|
+
try {
|
|
7037
|
+
await animation.finished;
|
|
7038
|
+
}
|
|
7039
|
+
catch {
|
|
7040
|
+
// Animation cancelled (e.g. superseded by a newer swap); the final
|
|
7041
|
+
// DOM state is already correct, so just fall through to cleanup.
|
|
7042
|
+
}
|
|
7043
|
+
finally {
|
|
7044
|
+
cleanup();
|
|
7045
|
+
}
|
|
7046
|
+
}
|
|
6959
7047
|
/**
|
|
6960
7048
|
* Get the effective autoNavigate value (defaults to autoSubmit if not set)
|
|
6961
7049
|
*/
|
|
@@ -7258,45 +7346,55 @@ class AuthheroWidget {
|
|
|
7258
7346
|
}
|
|
7259
7347
|
else if (!response.ok && result.screen) {
|
|
7260
7348
|
// Handle validation errors (400 response) — preserve user input
|
|
7261
|
-
this.
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7349
|
+
await this.swapScreen(() => {
|
|
7350
|
+
// Clear loading first so the captured "after" snapshot doesn't
|
|
7351
|
+
// freeze a disabled button into the cross-fade.
|
|
7352
|
+
this.loading = false;
|
|
7353
|
+
this._screen = result.screen;
|
|
7354
|
+
this.initFormDataFromDefaults(result.screen);
|
|
7355
|
+
this.screenChange.emit(result.screen);
|
|
7356
|
+
this.updateDataScreenAttribute();
|
|
7357
|
+
this.focusFirstInput();
|
|
7358
|
+
});
|
|
7266
7359
|
}
|
|
7267
7360
|
else if (result.screen) {
|
|
7268
7361
|
// Next screen (success)
|
|
7269
|
-
this.
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
this.
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
}
|
|
7284
|
-
// Apply branding if included
|
|
7285
|
-
if (result.branding) {
|
|
7286
|
-
this._branding = result.branding;
|
|
7287
|
-
this.applyThemeStyles();
|
|
7288
|
-
}
|
|
7289
|
-
// Update state if returned
|
|
7290
|
-
if (result.state) {
|
|
7291
|
-
this.state = result.state;
|
|
7362
|
+
await this.swapScreen(() => {
|
|
7363
|
+
// Clear loading first so the captured "after" snapshot doesn't
|
|
7364
|
+
// freeze a disabled button into the cross-fade.
|
|
7365
|
+
this.loading = false;
|
|
7366
|
+
this._screen = result.screen;
|
|
7367
|
+
this.formData = {};
|
|
7368
|
+
this.initFormDataFromDefaults(result.screen);
|
|
7369
|
+
this.screenChange.emit(result.screen);
|
|
7370
|
+
this.updateDataScreenAttribute();
|
|
7371
|
+
// Update screenId if returned in response
|
|
7372
|
+
if (result.screenId) {
|
|
7373
|
+
this.screenId = result.screenId;
|
|
7374
|
+
}
|
|
7375
|
+
// Persist state (especially for session storage mode)
|
|
7292
7376
|
this.persistState();
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7377
|
+
// Update URL path if navigateUrl is provided (client-side navigation)
|
|
7378
|
+
if (result.navigateUrl && this.shouldAutoNavigate) {
|
|
7379
|
+
window.history.pushState({ screen: result.screenId, state: this.state }, "", result.navigateUrl);
|
|
7380
|
+
}
|
|
7381
|
+
// Apply branding if included
|
|
7382
|
+
if (result.branding) {
|
|
7383
|
+
this._branding = result.branding;
|
|
7384
|
+
this.applyThemeStyles();
|
|
7385
|
+
}
|
|
7386
|
+
// Update state if returned
|
|
7387
|
+
if (result.state) {
|
|
7388
|
+
this.state = result.state;
|
|
7389
|
+
this.persistState();
|
|
7390
|
+
}
|
|
7391
|
+
// Perform WebAuthn ceremony if present (structured data, not script)
|
|
7392
|
+
if (result.ceremony) {
|
|
7393
|
+
this.performWebAuthnCeremony(result.ceremony);
|
|
7394
|
+
}
|
|
7395
|
+
// Focus first input on new screen
|
|
7396
|
+
this.focusFirstInput();
|
|
7397
|
+
});
|
|
7300
7398
|
}
|
|
7301
7399
|
else if (result.complete) {
|
|
7302
7400
|
// Flow complete without redirect
|