@dloizides/auth-web 1.10.0 → 1.11.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/index.js CHANGED
@@ -262,6 +262,14 @@ var DEFAULT_PREFERRED_METHOD_HINT_LABELS = {
262
262
  pin: "You usually sign in with your quick PIN on this account.",
263
263
  passkey: "You usually sign in with a passkey."
264
264
  };
265
+ var DEFAULT_DEMO_CREDENTIALS_HINT_LABELS = {
266
+ title: "Demo access",
267
+ description: "Explore the full product with our shared demo account.",
268
+ usernameLabel: "Username",
269
+ passwordLabel: "Password",
270
+ useCredentials: "Use these credentials",
271
+ useCredentialsHint: "Fill the sign-in form with the demo username and password"
272
+ };
265
273
  var DEFAULT_RESET_PASSWORD_LABELS = {
266
274
  title: "Reset password",
267
275
  description: "Choose a new password for your account.",
@@ -350,7 +358,12 @@ var AuthTestIds = {
350
358
  preferredMethodSettingsOption: "auth-preferred-method-settings-option",
351
359
  preferredMethodSettingsError: "auth-preferred-method-settings-error",
352
360
  // Preferred-method login-screen hint
353
- preferredMethodHint: "auth-preferred-method-hint"
361
+ preferredMethodHint: "auth-preferred-method-hint",
362
+ // Public-demo credentials panel
363
+ demoCredentialsHint: "auth-demo-credentials-hint",
364
+ demoCredentialsUsername: "auth-demo-credentials-username",
365
+ demoCredentialsPassword: "auth-demo-credentials-password",
366
+ demoCredentialsUseButton: "auth-demo-credentials-use"
354
367
  };
355
368
  function withTestIdPrefix(baseId, prefix) {
356
369
  return prefix === void 0 || prefix === "" ? baseId : `${prefix}-${baseId}`;
@@ -481,6 +494,21 @@ function useAuthStyles(theme) {
481
494
  });
482
495
  }, [theme]);
483
496
  }
497
+ function useLoginPrefill({
498
+ initialUsername,
499
+ initialPassword,
500
+ prefillNonce
501
+ }) {
502
+ const [username, setUsername] = react.useState(initialUsername ?? "");
503
+ const [password, setPassword] = react.useState(initialPassword ?? "");
504
+ const [appliedNonce, setAppliedNonce] = react.useState(prefillNonce);
505
+ if (prefillNonce !== appliedNonce) {
506
+ setAppliedNonce(prefillNonce);
507
+ setUsername(initialUsername ?? "");
508
+ setPassword(initialPassword ?? "");
509
+ }
510
+ return { username, password, setUsername, setPassword };
511
+ }
484
512
  var BffAuthStatus = /* @__PURE__ */ ((BffAuthStatus2) => {
485
513
  BffAuthStatus2["Loading"] = "loading";
486
514
  BffAuthStatus2["Authenticated"] = "authenticated";
@@ -592,7 +620,10 @@ function LoginForm({
592
620
  onForgotPassword,
593
621
  onSignUp,
594
622
  testIdPrefix,
595
- chromeless = false
623
+ chromeless = false,
624
+ initialUsername,
625
+ initialPassword,
626
+ prefillNonce
596
627
  }) {
597
628
  const theme = useAuthTheme(themeProp);
598
629
  const styles3 = useAuthStyles(theme);
@@ -601,8 +632,11 @@ function LoginForm({
601
632
  [labelsProp]
602
633
  );
603
634
  const { login, isSubmitting } = useBffAuth({ client, probeOnMount: false });
604
- const [username, setUsername] = react.useState("");
605
- const [password, setPassword] = react.useState("");
635
+ const { username, password, setUsername, setPassword } = useLoginPrefill({
636
+ initialUsername,
637
+ initialPassword,
638
+ prefillNonce
639
+ });
606
640
  const [errorText, setErrorText] = react.useState(null);
607
641
  const runLogin = react.useCallback(async () => {
608
642
  setErrorText(null);
@@ -3132,6 +3166,156 @@ function PreferredMethodHint({
3132
3166
  }
3133
3167
  return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: withTestIdPrefix(AuthTestIds.preferredMethodHint, testIdPrefix), children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.helperText, children: text }) });
3134
3168
  }
3169
+ var PANEL_BORDER_WIDTH = 1;
3170
+ var ACCENT_RAIL_WIDTH = 3;
3171
+ var TITLE_LETTER_SPACING = 0.8;
3172
+ var DESCRIPTION_LINE_HEIGHT_RATIO = 1.45;
3173
+ var HALF = 2;
3174
+ var MONOSPACE_FONT = reactNative.Platform.select({
3175
+ ios: "Menlo",
3176
+ android: "monospace",
3177
+ default: "monospace"
3178
+ });
3179
+ function useDemoCredentialsStyles(theme) {
3180
+ return react.useMemo(() => {
3181
+ const { colors, radii, spacing, typography } = theme;
3182
+ return reactNative.StyleSheet.create({
3183
+ panel: {
3184
+ borderWidth: PANEL_BORDER_WIDTH,
3185
+ borderLeftWidth: ACCENT_RAIL_WIDTH,
3186
+ borderRadius: radii.card,
3187
+ borderColor: colors.border,
3188
+ borderLeftColor: colors.primary,
3189
+ padding: spacing.md,
3190
+ marginBottom: spacing.md,
3191
+ backgroundColor: colors.background
3192
+ },
3193
+ title: {
3194
+ fontSize: typography.caption,
3195
+ fontWeight: "700",
3196
+ letterSpacing: TITLE_LETTER_SPACING,
3197
+ textTransform: "uppercase",
3198
+ color: colors.primary
3199
+ },
3200
+ description: {
3201
+ fontSize: typography.caption,
3202
+ lineHeight: typography.caption * DESCRIPTION_LINE_HEIGHT_RATIO,
3203
+ marginTop: spacing.xs / HALF,
3204
+ marginBottom: spacing.sm,
3205
+ color: colors.textSecondary
3206
+ },
3207
+ row: {
3208
+ flexDirection: "row",
3209
+ alignItems: "center",
3210
+ justifyContent: "space-between",
3211
+ marginTop: spacing.xs / HALF
3212
+ },
3213
+ rowLabel: {
3214
+ fontSize: typography.caption,
3215
+ color: colors.textSecondary
3216
+ },
3217
+ rowValue: {
3218
+ fontFamily: MONOSPACE_FONT,
3219
+ fontSize: typography.caption,
3220
+ fontWeight: "600",
3221
+ borderWidth: PANEL_BORDER_WIDTH,
3222
+ borderRadius: radii.input,
3223
+ borderColor: colors.border,
3224
+ paddingVertical: spacing.xs / HALF,
3225
+ paddingHorizontal: spacing.xs,
3226
+ // Never let a long password squeeze the label off the row.
3227
+ flexShrink: 1,
3228
+ backgroundColor: colors.surface,
3229
+ color: colors.text
3230
+ }
3231
+ });
3232
+ }, [theme]);
3233
+ }
3234
+
3235
+ // src/demo/resolveDemoCredentials.ts
3236
+ function resolveDemoCredentials(credentials) {
3237
+ if (credentials === void 0 || credentials === null) {
3238
+ return null;
3239
+ }
3240
+ const username = typeof credentials.username === "string" ? credentials.username.trim() : "";
3241
+ const password = typeof credentials.password === "string" ? credentials.password : "";
3242
+ const isUnusable = username.length === 0 || password.length === 0;
3243
+ if (isUnusable) {
3244
+ return null;
3245
+ }
3246
+ return { username, password };
3247
+ }
3248
+ function DemoCredentialsHint({
3249
+ credentials,
3250
+ theme: themeProp,
3251
+ labels: labelsProp,
3252
+ testIdPrefix,
3253
+ onUse
3254
+ }) {
3255
+ const theme = useAuthTheme(themeProp);
3256
+ const authStyles = useAuthStyles(theme);
3257
+ const styles3 = useDemoCredentialsStyles(theme);
3258
+ const labels = react.useMemo(
3259
+ () => ({ ...DEFAULT_DEMO_CREDENTIALS_HINT_LABELS, ...labelsProp }),
3260
+ [labelsProp]
3261
+ );
3262
+ const resolved = react.useMemo(() => resolveDemoCredentials(credentials), [credentials]);
3263
+ const handleUse = react.useCallback(() => {
3264
+ if (resolved !== null && onUse !== void 0) {
3265
+ onUse(resolved);
3266
+ }
3267
+ }, [resolved, onUse]);
3268
+ if (resolved === null) {
3269
+ return null;
3270
+ }
3271
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3272
+ reactNative.View,
3273
+ {
3274
+ style: styles3.panel,
3275
+ testID: withTestIdPrefix(AuthTestIds.demoCredentialsHint, testIdPrefix),
3276
+ children: [
3277
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
3278
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.description, children: labels.description }),
3279
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.row, children: [
3280
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.rowLabel, children: labels.usernameLabel }),
3281
+ /* @__PURE__ */ jsxRuntime.jsx(
3282
+ reactNative.Text,
3283
+ {
3284
+ selectable: true,
3285
+ style: styles3.rowValue,
3286
+ testID: withTestIdPrefix(AuthTestIds.demoCredentialsUsername, testIdPrefix),
3287
+ children: resolved.username
3288
+ }
3289
+ )
3290
+ ] }),
3291
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.row, children: [
3292
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.rowLabel, children: labels.passwordLabel }),
3293
+ /* @__PURE__ */ jsxRuntime.jsx(
3294
+ reactNative.Text,
3295
+ {
3296
+ selectable: true,
3297
+ style: styles3.rowValue,
3298
+ testID: withTestIdPrefix(AuthTestIds.demoCredentialsPassword, testIdPrefix),
3299
+ children: resolved.password
3300
+ }
3301
+ )
3302
+ ] }),
3303
+ onUse !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
3304
+ reactNative.TouchableOpacity,
3305
+ {
3306
+ accessibilityHint: labels.useCredentialsHint,
3307
+ accessibilityLabel: labels.useCredentials,
3308
+ accessibilityRole: "button",
3309
+ style: authStyles.secondaryButton,
3310
+ testID: withTestIdPrefix(AuthTestIds.demoCredentialsUseButton, testIdPrefix),
3311
+ onPress: handleUse,
3312
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: authStyles.secondaryButtonText, children: labels.useCredentials })
3313
+ }
3314
+ ) : null
3315
+ ]
3316
+ }
3317
+ );
3318
+ }
3135
3319
  var EMPTY_CONFIG = {
3136
3320
  methods: [],
3137
3321
  registrationEnabled: false,
@@ -3237,6 +3421,34 @@ async function syncPreferredMethodFromServer(client) {
3237
3421
  return null;
3238
3422
  }
3239
3423
  }
3424
+ function useDemoCredentials({
3425
+ credentials,
3426
+ prefillOnMount = false
3427
+ } = {}) {
3428
+ const resolved = react.useMemo(() => resolveDemoCredentials(credentials), [credentials]);
3429
+ const [filled, setFilled] = react.useState(
3430
+ prefillOnMount ? resolved : null
3431
+ );
3432
+ const [prefillNonce, setPrefillNonce] = react.useState(0);
3433
+ const handleUse = react.useCallback((next) => {
3434
+ setFilled(next);
3435
+ setPrefillNonce((current) => current + 1);
3436
+ }, []);
3437
+ return react.useMemo(
3438
+ () => ({
3439
+ loginFormProps: {
3440
+ initialUsername: filled?.username,
3441
+ initialPassword: filled?.password,
3442
+ prefillNonce
3443
+ },
3444
+ // `credentials` is passed through unresolved on purpose: the hint applies
3445
+ // `resolveDemoCredentials` itself, so it fails closed even when it is used
3446
+ // standalone, without this hook.
3447
+ hintProps: { credentials, onUse: handleUse }
3448
+ }),
3449
+ [filled, prefillNonce, credentials, handleUse]
3450
+ );
3451
+ }
3240
3452
  async function lazyFetchHttpClient(request) {
3241
3453
  const fetchImpl = typeof fetch === "function" ? fetch.bind(globalThis) : void 0;
3242
3454
  if (fetchImpl === void 0) {
@@ -3336,6 +3548,7 @@ exports.AuthTestIds = AuthTestIds;
3336
3548
  exports.AuthThemeProvider = AuthThemeProvider;
3337
3549
  exports.BffAuthStatus = BffAuthStatus;
3338
3550
  exports.DEFAULT_AUTH_CARD_MAX_WIDTH = DEFAULT_AUTH_CARD_MAX_WIDTH;
3551
+ exports.DEFAULT_DEMO_CREDENTIALS_HINT_LABELS = DEFAULT_DEMO_CREDENTIALS_HINT_LABELS;
3339
3552
  exports.DEFAULT_DEVICE_PIN_ENROLL_LABELS = DEFAULT_DEVICE_PIN_ENROLL_LABELS;
3340
3553
  exports.DEFAULT_DEVICE_PIN_SETTINGS_LABELS = DEFAULT_DEVICE_PIN_SETTINGS_LABELS;
3341
3554
  exports.DEFAULT_DEVICE_PIN_UNLOCK_LABELS = DEFAULT_DEVICE_PIN_UNLOCK_LABELS;
@@ -3351,6 +3564,7 @@ exports.DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS = DEFAULT_PREFERRED_METHOD_SETT
3351
3564
  exports.DEFAULT_RESET_PASSWORD_LABELS = DEFAULT_RESET_PASSWORD_LABELS;
3352
3565
  exports.DEVICE_PIN_ALLOWED_DIGITS = DEVICE_PIN_ALLOWED_DIGITS;
3353
3566
  exports.DEVICE_PIN_DEFAULT_DIGITS = DEVICE_PIN_DEFAULT_DIGITS;
3567
+ exports.DemoCredentialsHint = DemoCredentialsHint;
3354
3568
  exports.DevicePinEnrollErrorKey = DevicePinEnrollErrorKey;
3355
3569
  exports.DevicePinEnrollForm = DevicePinEnrollForm;
3356
3570
  exports.DevicePinErrorKey = DevicePinErrorKey;
@@ -3390,6 +3604,7 @@ exports.readCachedPreferredMethod = readCachedPreferredMethod;
3390
3604
  exports.readPasskeyError = readPasskeyError;
3391
3605
  exports.readPasskeyRegistered = readPasskeyRegistered;
3392
3606
  exports.resolveAccessibleRoutes = resolveAccessibleRoutes;
3607
+ exports.resolveDemoCredentials = resolveDemoCredentials;
3393
3608
  exports.resolvePostLoginRoute = resolvePostLoginRoute;
3394
3609
  exports.startPasskeyLogin = startPasskeyLogin;
3395
3610
  exports.startPasskeyRegistration = startPasskeyRegistration;
@@ -3399,6 +3614,7 @@ exports.useBffAuth = useBffAuth;
3399
3614
  exports.useBffForgotPassword = useBffForgotPassword;
3400
3615
  exports.useBffLoginConfig = useBffLoginConfig;
3401
3616
  exports.useBffResetPassword = useBffResetPassword;
3617
+ exports.useDemoCredentials = useDemoCredentials;
3402
3618
  exports.useDevicePinDisable = useDevicePinDisable;
3403
3619
  exports.useDevicePinEnroll = useDevicePinEnroll;
3404
3620
  exports.useDevicePinUnlock = useDevicePinUnlock;