@zitadel/components 0.1.0-alpha.0 → 0.1.0-alpha.10

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.
Files changed (106) hide show
  1. package/README.md +76 -55
  2. package/dist/atoms/index.d.mts +1 -1
  3. package/dist/atoms/index.mjs +1 -1
  4. package/dist/{atoms-B9yd0c-i.mjs → atoms-BaayzEsr.mjs} +229 -88
  5. package/dist/atoms-BaayzEsr.mjs.map +1 -0
  6. package/dist/default-Cpl78hQN.mjs +6 -0
  7. package/dist/default-Cpl78hQN.mjs.map +1 -0
  8. package/dist/{index-B74_igDN.d.mts → index-DB_JTtln.d.mts} +86 -19
  9. package/dist/index-DB_JTtln.d.mts.map +1 -0
  10. package/dist/{index-Dd8hfOWt.d.mts → index-DVDCrfkv.d.mts} +1515 -827
  11. package/dist/index-DVDCrfkv.d.mts.map +1 -0
  12. package/dist/index.d.mts +3 -3
  13. package/dist/index.mjs +4 -4
  14. package/dist/manifests.mjs +1 -1
  15. package/dist/orchestrator/index.d.mts +2 -2
  16. package/dist/orchestrator/index.mjs +2 -2
  17. package/dist/{orchestrator-B8eXcPRi.mjs → orchestrator-BEvS2wA_.mjs} +444 -162
  18. package/dist/orchestrator-BEvS2wA_.mjs.map +1 -0
  19. package/dist/standalone.mjs +12156 -0
  20. package/dist/tokens/index.mjs +1 -1
  21. package/dist/{tokens-TXmurodq.mjs → tokens-BQ_augxi.mjs} +2 -2
  22. package/dist/{tokens-TXmurodq.mjs.map → tokens-BQ_augxi.mjs.map} +1 -1
  23. package/package.json +9 -17
  24. package/dist/atoms/index.d.ts +0 -9
  25. package/dist/atoms/index.d.ts.map +0 -1
  26. package/dist/atoms/zl-alert.d.ts +0 -56
  27. package/dist/atoms/zl-alert.d.ts.map +0 -1
  28. package/dist/atoms/zl-button.d.ts +0 -83
  29. package/dist/atoms/zl-button.d.ts.map +0 -1
  30. package/dist/atoms/zl-card.d.ts +0 -46
  31. package/dist/atoms/zl-card.d.ts.map +0 -1
  32. package/dist/atoms/zl-field.d.ts +0 -80
  33. package/dist/atoms/zl-field.d.ts.map +0 -1
  34. package/dist/atoms/zl-icon.d.ts +0 -48
  35. package/dist/atoms/zl-icon.d.ts.map +0 -1
  36. package/dist/atoms/zl-page-shell.d.ts +0 -42
  37. package/dist/atoms/zl-page-shell.d.ts.map +0 -1
  38. package/dist/atoms/zl-passkey.d.ts +0 -123
  39. package/dist/atoms/zl-passkey.d.ts.map +0 -1
  40. package/dist/atoms/zl-pill.d.ts +0 -55
  41. package/dist/atoms/zl-pill.d.ts.map +0 -1
  42. package/dist/atoms-B9yd0c-i.mjs.map +0 -1
  43. package/dist/default-DP74t2io.mjs +0 -6
  44. package/dist/default-DP74t2io.mjs.map +0 -1
  45. package/dist/index-B74_igDN.d.mts.map +0 -1
  46. package/dist/index-Dd8hfOWt.d.mts.map +0 -1
  47. package/dist/index.d.ts +0 -16
  48. package/dist/index.d.ts.map +0 -1
  49. package/dist/internal/base64url.d.ts +0 -18
  50. package/dist/internal/base64url.d.ts.map +0 -1
  51. package/dist/internal/unique-id.d.ts +0 -2
  52. package/dist/internal/unique-id.d.ts.map +0 -1
  53. package/dist/manifest.d.ts +0 -36
  54. package/dist/manifest.d.ts.map +0 -1
  55. package/dist/manifests.d.ts +0 -6
  56. package/dist/manifests.d.ts.map +0 -1
  57. package/dist/orchestrator/api-client.d.ts +0 -33
  58. package/dist/orchestrator/api-client.d.ts.map +0 -1
  59. package/dist/orchestrator/branding-to-tokens.d.ts +0 -28
  60. package/dist/orchestrator/branding-to-tokens.d.ts.map +0 -1
  61. package/dist/orchestrator/branding-validator.d.ts +0 -7
  62. package/dist/orchestrator/branding-validator.d.ts.map +0 -1
  63. package/dist/orchestrator/branding.d.ts +0 -76
  64. package/dist/orchestrator/branding.d.ts.map +0 -1
  65. package/dist/orchestrator/font-loader.d.ts +0 -2
  66. package/dist/orchestrator/font-loader.d.ts.map +0 -1
  67. package/dist/orchestrator/index.d.ts +0 -23
  68. package/dist/orchestrator/index.d.ts.map +0 -1
  69. package/dist/orchestrator/liquid.d.ts +0 -31
  70. package/dist/orchestrator/liquid.d.ts.map +0 -1
  71. package/dist/orchestrator/locales/de.d.ts +0 -16
  72. package/dist/orchestrator/locales/de.d.ts.map +0 -1
  73. package/dist/orchestrator/locales/en.d.ts +0 -19
  74. package/dist/orchestrator/locales/en.d.ts.map +0 -1
  75. package/dist/orchestrator/locales/index.d.ts +0 -13
  76. package/dist/orchestrator/locales/index.d.ts.map +0 -1
  77. package/dist/orchestrator/locales/it.d.ts +0 -14
  78. package/dist/orchestrator/locales/it.d.ts.map +0 -1
  79. package/dist/orchestrator/mandatory-gates.d.ts +0 -26
  80. package/dist/orchestrator/mandatory-gates.d.ts.map +0 -1
  81. package/dist/orchestrator/sanitiser.d.ts +0 -6
  82. package/dist/orchestrator/sanitiser.d.ts.map +0 -1
  83. package/dist/orchestrator/template-context.d.ts +0 -55
  84. package/dist/orchestrator/template-context.d.ts.map +0 -1
  85. package/dist/orchestrator/template-names.d.ts +0 -16
  86. package/dist/orchestrator/template-names.d.ts.map +0 -1
  87. package/dist/orchestrator/theme-controller.d.ts +0 -30
  88. package/dist/orchestrator/theme-controller.d.ts.map +0 -1
  89. package/dist/orchestrator/zitadel-login.d.ts +0 -185
  90. package/dist/orchestrator/zitadel-login.d.ts.map +0 -1
  91. package/dist/orchestrator/zitadel-logout.d.ts +0 -86
  92. package/dist/orchestrator/zitadel-logout.d.ts.map +0 -1
  93. package/dist/orchestrator-B8eXcPRi.mjs.map +0 -1
  94. package/dist/styles/base.d.ts +0 -7
  95. package/dist/styles/base.d.ts.map +0 -1
  96. package/dist/styles/focus-ring.d.ts +0 -7
  97. package/dist/styles/focus-ring.d.ts.map +0 -1
  98. package/dist/styles/index.d.ts +0 -5
  99. package/dist/styles/index.d.ts.map +0 -1
  100. package/dist/styles/surface.d.ts +0 -8
  101. package/dist/styles/surface.d.ts.map +0 -1
  102. package/dist/styles/tokens.d.ts +0 -11
  103. package/dist/styles/tokens.d.ts.map +0 -1
  104. package/dist/tokens/index.d.ts +0 -9
  105. package/dist/tokens/index.d.ts.map +0 -1
  106. package/dist/tsconfig.lib.tsbuildinfo +0 -1
@@ -1,14 +1,36 @@
1
- import { t as cssVars } from "./tokens-TXmurodq.mjs";
1
+ import { t as cssVars } from "./tokens-BQ_augxi.mjs";
2
2
  import { LitElement, css, html, nothing, unsafeCSS } from "lit";
3
- import { customElement, property, state } from "lit/decorators.js";
3
+ import { customElement, property, query, state } from "lit/decorators.js";
4
+ import { classMap } from "lit/directives/class-map.js";
4
5
  import { unsafeSVG } from "lit/directives/unsafe-svg.js";
5
6
  import { ArrowLeft, ArrowRight, Check, CircleAlert, Eye, EyeOff, Info, KeyRound, LoaderCircle, Plus, TriangleAlert, User, X } from "lucide";
7
+ import { ifDefined } from "lit/directives/if-defined.js";
8
+ import { live } from "lit/directives/live.js";
6
9
  //#region ../shared-component-styles/src/lit/alert-host.css?inline
7
10
  var alert_host_default = ":host {\n display: block;\n}\n";
8
11
  //#endregion
9
12
  //#region ../shared-component-styles/src/alert.css?inline
10
13
  var alert_default = ".zr-alert {\n align-items: flex-start;\n gap: var(--zl-spacing-03, 1rem);\n padding: var(--zl-spacing-03, 1rem);\n border-radius: var(--zl-radius-m, .75rem);\n background: var(--zl-color-surface-default-primary-gray, #252528);\n color: var(--zl-color-text-button-invert, #f4f4f6);\n font-family: var(--zl-font-family-sans, system-ui, sans-serif);\n font-size: .875rem;\n font-weight: 400;\n line-height: 1.25rem;\n display: flex;\n box-shadow: 0 1px 2px #1018280d;\n}\n\n.zr-alert__icon {\n color: var(--zl-color-text-error, #ea4f70);\n flex-shrink: 0;\n}\n\n.zr-alert--warning .zr-alert__icon {\n color: var(--zl-color-text-subtitle-orange, #f25543);\n}\n\n.zr-alert--success .zr-alert__icon {\n color: var(--zl-color-text-success, #33a779);\n}\n\n.zr-alert--info .zr-alert__icon {\n color: var(--zl-color-text-subtitle-gray, #bfbfcf);\n}\n\n.zr-alert__body {\n gap: var(--zl-spacing-01, .25rem);\n flex-direction: column;\n flex: auto;\n min-width: 0;\n display: flex;\n}\n\n.zr-alert__title {\n color: var(--zl-color-text-button-invert, #f4f4f6);\n font-weight: 600;\n}\n\n.zr-alert__message {\n color: var(--zl-color-border-default-white, #f4f4f6);\n margin: 0;\n}\n\n.zr-alert:not(:has(.zr-alert__title)) .zr-alert__message {\n color: var(--zl-color-text-button-invert, #f4f4f6);\n}\n\n.zr-alert__close {\n all: unset;\n width: 2.25rem;\n height: 2.25rem;\n padding: var(--zl-spacing-02, .5rem);\n border-radius: var(--zl-radius-s, .5rem);\n color: var(--zl-color-text-secondary-gray, #bfbfcf);\n cursor: pointer;\n transition: background-color var(--zl-duration-fast, .12s) var(--zl-easing-standard, cubic-bezier(.2, 0, 0, 1));\n flex-shrink: 0;\n justify-content: center;\n align-items: center;\n display: inline-flex;\n}\n\n.zr-alert__close .zr-icon {\n --zl-icon-size: 1.25rem;\n width: 1.25rem;\n height: 1.25rem;\n}\n\n.zr-alert__close:hover {\n background: var(--zl-color-gray-200, #484a57);\n}\n\n.zr-alert__close:focus-visible {\n outline: var(--zl-focus-width, 2px) solid var(--zl-focus-color, #f4f4f6);\n outline-offset: var(--zl-focus-offset, 2px);\n}\n";
11
14
  //#endregion
15
+ //#region src/internal/emit.ts
16
+ /**
17
+ * Dispatch a custom event with the project-wide defaults (`bubbles` +
18
+ * `composed`) so it crosses the shadow boundary and reaches delegated
19
+ * listeners — whether it's an atom's `zl-*` event or the orchestrator's
20
+ * public `zitadel-*` event.
21
+ *
22
+ * Centralising the dispatch shape keeps every event contract identical and
23
+ * removes the repeated `new CustomEvent(..., { bubbles: true, composed: true,
24
+ * detail })` boilerplate.
25
+ */
26
+ function emit(host, type, detail) {
27
+ return host.dispatchEvent(new CustomEvent(type, {
28
+ bubbles: true,
29
+ composed: true,
30
+ detail
31
+ }));
32
+ }
33
+ //#endregion
12
34
  //#region src/styles/tokens.ts
13
35
  function wrap(node) {
14
36
  if (typeof node === "string") return unsafeCSS(node);
@@ -123,12 +145,12 @@ let ZlIcon = class ZlIcon extends LitElement {
123
145
  const ariaLabel = this.label ?? DEFAULT_LABELS[this.name];
124
146
  const hidden = this.decorative || !ariaLabel;
125
147
  return html`
126
- <span class=${[
127
- "zr-icon",
128
- `zr-icon--${this.size}`,
129
- this.tone !== "default" ? `zr-icon--tone-${this.tone}` : "",
130
- this.spin ? "zr-icon--spin" : ""
131
- ].filter(Boolean).join(" ")}>
148
+ <span class=${classMap({
149
+ "zr-icon": true,
150
+ [`zr-icon--${this.size}`]: true,
151
+ [`zr-icon--tone-${this.tone}`]: this.tone !== "default",
152
+ "zr-icon--spin": this.spin
153
+ })}>
132
154
  <svg
133
155
  viewBox="0 0 24 24"
134
156
  fill="none"
@@ -257,10 +279,7 @@ let ZlAlert = class ZlAlert extends LitElement {
257
279
  `;
258
280
  }
259
281
  handleDismiss = () => {
260
- this.dispatchEvent(new CustomEvent("zl-dismiss", {
261
- bubbles: true,
262
- composed: true
263
- }));
282
+ emit(this, "zl-dismiss");
264
283
  this.remove();
265
284
  };
266
285
  };
@@ -292,7 +311,7 @@ const zlAlertManifest = {
292
311
  "message",
293
312
  "close"
294
313
  ],
295
- slots: [],
314
+ slots: [""],
296
315
  events: ["zl-dismiss"]
297
316
  };
298
317
  //#endregion
@@ -366,63 +385,116 @@ let ZlButton = class ZlButton extends LitElement {
366
385
  set label(value) {
367
386
  this.#_label_accessor_storage = value;
368
387
  }
388
+ #_testId_accessor_storage = void 0;
389
+ get testId() {
390
+ return this.#_testId_accessor_storage;
391
+ }
392
+ set testId(value) {
393
+ this.#_testId_accessor_storage = value;
394
+ }
395
+ #_forcedState_accessor_storage = null;
396
+ get forcedState() {
397
+ return this.#_forcedState_accessor_storage;
398
+ }
399
+ set forcedState(value) {
400
+ this.#_forcedState_accessor_storage = value;
401
+ }
369
402
  internals;
370
403
  constructor() {
371
404
  super();
372
405
  this.internals = this.attachInternals();
373
406
  }
407
+ connectedCallback() {
408
+ super.connectedCallback();
409
+ this.addEventListener("click", this.handleHostClick);
410
+ }
411
+ disconnectedCallback() {
412
+ this.removeEventListener("click", this.handleHostClick);
413
+ super.disconnectedCallback();
414
+ }
374
415
  focus(options) {
375
416
  this.shadowRoot?.querySelector("button")?.focus(options);
376
417
  }
377
- surfaceClasses() {
378
- return [
379
- "root",
380
- "zr-btn",
381
- `zr-btn--${this.hierarchy}`,
382
- `zr-btn--${this.size}`,
383
- this.block ? "zr-btn--block" : ""
384
- ].filter(Boolean).join(" ");
385
- }
386
418
  render() {
387
- const blocked = this.disabled || this.loading;
388
- const forcedState = this.getAttribute("data-state");
389
- const body = this.label !== void 0 ? html`<span>${this.label}</span>` : html`<slot></slot>`;
419
+ const hierarchy = this.stringOption("hierarchy", this.hierarchy, "primary");
420
+ const size = this.stringOption("size", this.size, "medium");
421
+ const type = this.buttonType();
422
+ const loading = this.booleanOption("loading", this.loading);
423
+ const disabled = this.booleanOption("disabled", this.disabled);
424
+ const block = this.booleanOption("block", this.block);
425
+ const label = this.stringOption("label", this.label);
426
+ const blocked = disabled || loading;
427
+ const body = label !== void 0 ? html`<span>${label}</span>` : html`<slot></slot>`;
390
428
  return html`
391
429
  <button
392
- class=${this.surfaceClasses()}
430
+ class=${classMap({
431
+ root: true,
432
+ "zr-btn": true,
433
+ [`zr-btn--${hierarchy}`]: true,
434
+ [`zr-btn--${size}`]: true,
435
+ "zr-btn--block": block
436
+ })}
393
437
  part="root"
394
- type=${this.type}
438
+ type=${type}
395
439
  ?disabled=${blocked}
396
- aria-busy=${this.loading ? "true" : "false"}
397
- data-state=${forcedState ?? nothing}
440
+ aria-busy=${loading ? "true" : "false"}
441
+ data-testid=${this.nativeButtonTestId() ?? nothing}
442
+ data-state=${this.forcedState ?? nothing}
398
443
  @click=${this.handleClick}
399
444
  >
400
445
  <slot name="leading"></slot>
401
446
  ${body}
402
- ${this.loading ? html`<span class="spinner" part="spinner"><zl-icon name="spinner" size=${this.size === "small" ? "16" : "24"} spin decorative></zl-icon></span>` : html`<slot name="trailing"></slot>`}
447
+ ${loading ? html`<span class="spinner" part="spinner"><zl-icon name="spinner" size=${size === "small" ? "16" : "24"} spin decorative></zl-icon></span>` : html`<slot name="trailing"></slot>`}
403
448
  </button>
404
449
  `;
405
450
  }
406
451
  handleClick = (event) => {
407
- if (this.disabled || this.loading) {
452
+ this.activate(event);
453
+ };
454
+ handleHostClick = (event) => {
455
+ if (event.composedPath()[0] !== this) return;
456
+ this.activate(event);
457
+ };
458
+ nativeButtonTestId() {
459
+ const testId = this.stringOption("data-testid", this.testId);
460
+ if (testId) return `${testId}-button`;
461
+ const action = this.buttonAction();
462
+ return action ? `zitadel-action-${action}` : void 0;
463
+ }
464
+ buttonType() {
465
+ const type = this.stringOption("type", this.type, "button");
466
+ return type === "submit" || type === "reset" ? type : "button";
467
+ }
468
+ buttonAction() {
469
+ return this.stringOption("action", this.action);
470
+ }
471
+ activate(event) {
472
+ const type = this.buttonType();
473
+ const action = this.buttonAction();
474
+ if (this.booleanOption("disabled", this.disabled) || this.booleanOption("loading", this.loading)) {
408
475
  event.preventDefault();
409
476
  event.stopImmediatePropagation();
410
477
  return;
411
478
  }
412
479
  const form = this.internals.form;
413
- if (this.type === "submit" && form) {
480
+ if (type === "submit" && form) {
414
481
  event.preventDefault();
415
482
  form.requestSubmit();
416
- } else if (this.type === "reset" && form) {
483
+ } else if (type === "reset" && form) {
417
484
  event.preventDefault();
418
485
  form.reset();
419
486
  }
420
- this.dispatchEvent(new CustomEvent("zl-submit", {
421
- bubbles: true,
422
- composed: true,
423
- detail: { action: this.action ?? null }
424
- }));
425
- };
487
+ emit(this, "zl-submit", { action: action ?? null });
488
+ }
489
+ stringOption(attribute, value, fallback) {
490
+ if (typeof value === "string" && value.length > 0) return value;
491
+ const attr = this.getAttribute(attribute);
492
+ if (attr !== null && attr.length > 0) return attr;
493
+ return fallback;
494
+ }
495
+ booleanOption(attribute, value) {
496
+ return value === true || this.hasAttribute(attribute);
497
+ }
426
498
  };
427
499
  __decorate([property({ reflect: true })], ZlButton.prototype, "hierarchy", null);
428
500
  __decorate([property({ reflect: true })], ZlButton.prototype, "size", null);
@@ -438,6 +510,8 @@ __decorate([property({
438
510
  reflect: true
439
511
  })], ZlButton.prototype, "block", null);
440
512
  __decorate([property()], ZlButton.prototype, "label", null);
513
+ __decorate([property({ attribute: "data-testid" })], ZlButton.prototype, "testId", null);
514
+ __decorate([property({ attribute: "data-state" })], ZlButton.prototype, "forcedState", null);
441
515
  ZlButton = __decorate([customElement("zl-button")], ZlButton);
442
516
  const zlButtonManifest = {
443
517
  tag: "zl-button",
@@ -453,7 +527,8 @@ const zlButtonManifest = {
453
527
  "loading",
454
528
  "disabled",
455
529
  "block",
456
- "label"
530
+ "label",
531
+ "data-testid"
457
532
  ],
458
533
  parts: ["root", "spinner"],
459
534
  slots: [
@@ -483,20 +558,32 @@ let ZlCard = class ZlCard extends LitElement {
483
558
  render() {
484
559
  const hasHeader = this.lightDomSlotFilled("header");
485
560
  const hasFooter = this.lightDomSlotFilled("footer");
561
+ const cardClass = this.compact ? "zr-card zr-card--compact" : "zr-card";
562
+ const headerClass = hasHeader ? "zr-card__header" : "zr-card__header zr-card__region--empty";
563
+ const footerClass = hasFooter ? "zr-card__footer" : "zr-card__footer zr-card__region--empty";
486
564
  return html`
487
- <section class=${this.compact ? "zr-card zr-card--compact" : "zr-card"} part="card">
488
- <header class=${hasHeader ? "zr-card__header" : "zr-card__header zr-card__region--empty"} part="header">
489
- <slot name="header"></slot>
565
+ <section class=${cardClass} part="card">
566
+ <header class=${headerClass} part="header">
567
+ <slot name="header" @slotchange=${this.onSlotChange}></slot>
490
568
  </header>
491
569
  <div class="zr-card__body" part="body">
492
570
  <slot></slot>
493
571
  </div>
494
- <footer class=${hasFooter ? "zr-card__footer" : "zr-card__footer zr-card__region--empty"} part="footer">
495
- <slot name="footer"></slot>
572
+ <footer class=${footerClass} part="footer">
573
+ <slot name="footer" @slotchange=${this.onSlotChange}></slot>
496
574
  </footer>
497
575
  </section>
498
576
  `;
499
577
  }
578
+ /**
579
+ * `lightDomSlotFilled` is a render-time snapshot, so re-run render whenever a
580
+ * named slot's assignment changes (e.g. a header added after first paint).
581
+ * The initial render still reads children synchronously, avoiding the
582
+ * empty-then-filled flash a slotchange-only approach would introduce.
583
+ */
584
+ onSlotChange = () => {
585
+ this.requestUpdate();
586
+ };
500
587
  /** Slotted nodes are always light-DOM children of the host in our templates. */
501
588
  lightDomSlotFilled(slot) {
502
589
  for (const child of this.children) if (child.getAttribute("slot") === slot) return true;
@@ -625,6 +712,13 @@ let ZlField = class ZlField extends LitElement {
625
712
  set success(value) {
626
713
  this.#_success_accessor_storage = value;
627
714
  }
715
+ #_testId_accessor_storage = void 0;
716
+ get testId() {
717
+ return this.#_testId_accessor_storage;
718
+ }
719
+ set testId(value) {
720
+ this.#_testId_accessor_storage = value;
721
+ }
628
722
  #_forgotPasswordHref_accessor_storage = void 0;
629
723
  get forgotPasswordHref() {
630
724
  return this.#_forgotPasswordHref_accessor_storage;
@@ -681,6 +775,13 @@ let ZlField = class ZlField extends LitElement {
681
775
  set hasSuffixSlot(value) {
682
776
  this.#_hasSuffixSlot_accessor_storage = value;
683
777
  }
778
+ #_inputEl_accessor_storage = null;
779
+ get inputEl() {
780
+ return this.#_inputEl_accessor_storage;
781
+ }
782
+ set inputEl(value) {
783
+ this.#_inputEl_accessor_storage = value;
784
+ }
684
785
  inputId = nextUid("zl-field");
685
786
  internals;
686
787
  constructor() {
@@ -701,7 +802,7 @@ let ZlField = class ZlField extends LitElement {
701
802
  this.value = state ?? "";
702
803
  }
703
804
  focus(options) {
704
- this.shadowRoot?.querySelector("input")?.focus(options);
805
+ this.inputEl?.focus(options);
705
806
  }
706
807
  render() {
707
808
  const labelId = `${this.inputId}-label`;
@@ -715,15 +816,18 @@ let ZlField = class ZlField extends LitElement {
715
816
  showSuccess ? successId : null,
716
817
  this.hasHelp ? helpId : null
717
818
  ].filter(Boolean).join(" ");
718
- const rootClass = [
719
- "zr-field",
720
- this.invalid || showError ? "zr-field--invalid" : "",
721
- showSuccess ? "zr-field--success" : "",
722
- this.disabled ? "zr-field--disabled" : ""
723
- ].filter(Boolean).join(" ");
819
+ const rootClass = classMap({
820
+ "zr-field": true,
821
+ "zr-field--invalid": this.invalid || showError,
822
+ "zr-field--success": showSuccess,
823
+ "zr-field--disabled": this.disabled
824
+ });
724
825
  const showDefaultTrailing = this.trailingIcon && !this.hasSuffixSlot && !this.disabled;
725
826
  const trailing = showDefaultTrailing ? this.renderTrailingIcon() : null;
726
- const wrapClass = ["zr-field__wrap", showDefaultTrailing ? "zr-field__wrap--trailing" : ""].filter(Boolean).join(" ");
827
+ const wrapClass = classMap({
828
+ "zr-field__wrap": true,
829
+ "zr-field__wrap--trailing": showDefaultTrailing
830
+ });
727
831
  return html`
728
832
  <div class=${rootClass} part="root">
729
833
  ${this.renderLabelRow(labelId)}
@@ -733,12 +837,13 @@ let ZlField = class ZlField extends LitElement {
733
837
  class="zr-field__input"
734
838
  part="input"
735
839
  id=${this.inputId}
840
+ data-testid=${ifDefined(this.nativeInputTestId())}
736
841
  name=${this.name}
737
842
  type=${this.type}
738
- .value=${this.value}
843
+ .value=${live(this.value)}
739
844
  placeholder=${this.placeholder}
740
- autocomplete=${this.autocomplete ?? ""}
741
- pattern=${this.pattern ?? ""}
845
+ autocomplete=${ifDefined(this.autocomplete)}
846
+ pattern=${ifDefined(this.pattern)}
742
847
  ?required=${this.required}
743
848
  ?disabled=${this.disabled}
744
849
  aria-invalid=${this.invalid || showError ? "true" : "false"}
@@ -834,36 +939,31 @@ let ZlField = class ZlField extends LitElement {
834
939
  };
835
940
  handleClear = () => {
836
941
  this.value = "";
837
- this.dispatchEvent(new CustomEvent("zl-input", {
838
- bubbles: true,
839
- composed: true,
840
- detail: {
841
- name: this.name,
842
- value: this.value
843
- }
844
- }));
942
+ emit(this, "zl-input", {
943
+ name: this.name,
944
+ value: this.value
945
+ });
845
946
  this.syncFormState();
846
- this.shadowRoot?.querySelector(".zr-field__input")?.focus();
947
+ this.dispatchNativeInput();
948
+ this.inputEl?.focus();
847
949
  };
848
950
  handleInput = (event) => {
951
+ event.stopPropagation();
849
952
  const input = event.target;
850
953
  this.value = input.value;
851
- this.dispatchEvent(new CustomEvent("zl-input", {
852
- bubbles: true,
853
- composed: true,
854
- detail: {
855
- name: this.name,
856
- value: this.value
857
- }
858
- }));
954
+ this.syncFormState();
955
+ emit(this, "zl-input", {
956
+ name: this.name,
957
+ value: this.value
958
+ });
959
+ this.dispatchNativeInput(event);
859
960
  };
860
961
  handleChange = (event) => {
962
+ event.stopPropagation();
861
963
  const input = event.target;
862
964
  this.value = input.value;
863
- this.dispatchEvent(new Event("change", {
864
- bubbles: true,
865
- composed: true
866
- }));
965
+ this.syncFormState();
966
+ this.dispatchNativeChange();
867
967
  };
868
968
  handleKeyDown = (event) => {
869
969
  if (event.key === "Enter" && !event.isComposing && !event.shiftKey && !event.altKey && !event.metaKey && !event.ctrlKey) {
@@ -874,6 +974,33 @@ let ZlField = class ZlField extends LitElement {
874
974
  }
875
975
  }
876
976
  };
977
+ nativeInputTestId() {
978
+ if (this.name) return `zitadel-input-${this.name}`;
979
+ if (this.testId) return `${this.testId}-input`;
980
+ }
981
+ dispatchNativeInput(source) {
982
+ if (typeof InputEvent === "function") {
983
+ const input = source instanceof InputEvent ? source : void 0;
984
+ this.dispatchEvent(new InputEvent("input", {
985
+ bubbles: true,
986
+ composed: true,
987
+ data: input?.data ?? null,
988
+ inputType: input?.inputType ?? "",
989
+ isComposing: input?.isComposing ?? false
990
+ }));
991
+ return;
992
+ }
993
+ this.dispatchEvent(new Event("input", {
994
+ bubbles: true,
995
+ composed: true
996
+ }));
997
+ }
998
+ dispatchNativeChange() {
999
+ this.dispatchEvent(new Event("change", {
1000
+ bubbles: true,
1001
+ composed: true
1002
+ }));
1003
+ }
877
1004
  };
878
1005
  __decorate([property()], ZlField.prototype, "label", null);
879
1006
  __decorate([property()], ZlField.prototype, "type", null);
@@ -883,6 +1010,7 @@ __decorate([property()], ZlField.prototype, "autocomplete", null);
883
1010
  __decorate([property()], ZlField.prototype, "pattern", null);
884
1011
  __decorate([property()], ZlField.prototype, "error", null);
885
1012
  __decorate([property()], ZlField.prototype, "success", null);
1013
+ __decorate([property({ attribute: "data-testid" })], ZlField.prototype, "testId", null);
886
1014
  __decorate([property({ attribute: "forgot-password-href" })], ZlField.prototype, "forgotPasswordHref", null);
887
1015
  __decorate([property({ attribute: "forgot-password-label" })], ZlField.prototype, "forgotPasswordLabel", null);
888
1016
  __decorate([property({
@@ -900,6 +1028,7 @@ __decorate([property({
900
1028
  })], ZlField.prototype, "invalid", null);
901
1029
  __decorate([state()], ZlField.prototype, "hasHelp", null);
902
1030
  __decorate([state()], ZlField.prototype, "hasSuffixSlot", null);
1031
+ __decorate([query(".zr-field__input")], ZlField.prototype, "inputEl", null);
903
1032
  ZlField = __decorate([customElement("zl-field")], ZlField);
904
1033
  const zlFieldManifest = {
905
1034
  tag: "zl-field",
@@ -912,6 +1041,7 @@ const zlFieldManifest = {
912
1041
  "placeholder",
913
1042
  "autocomplete",
914
1043
  "pattern",
1044
+ "data-testid",
915
1045
  "required",
916
1046
  "disabled",
917
1047
  "invalid",
@@ -954,20 +1084,30 @@ let ZlPageShell = class ZlPageShell extends LitElement {
954
1084
  render() {
955
1085
  const hasHeader = this.lightDomSlotFilled("header");
956
1086
  const hasFooter = this.lightDomSlotFilled("footer");
1087
+ const headerClass = hasHeader ? "zr-page-shell__header" : "zr-page-shell__header zr-page-shell__region--empty";
1088
+ const footerClass = hasFooter ? "zr-page-shell__footer" : "zr-page-shell__footer zr-page-shell__region--empty";
957
1089
  return html`
958
1090
  <div class="zr-page-shell" part="shell">
959
- <header class=${hasHeader ? "zr-page-shell__header" : "zr-page-shell__header zr-page-shell__region--empty"} part="header">
960
- <slot name="header"></slot>
1091
+ <header class=${headerClass} part="header">
1092
+ <slot name="header" @slotchange=${this.onSlotChange}></slot>
961
1093
  </header>
962
1094
  <main class="zr-page-shell__main" part="main">
963
1095
  <slot></slot>
964
1096
  </main>
965
- <footer class=${hasFooter ? "zr-page-shell__footer" : "zr-page-shell__footer zr-page-shell__region--empty"} part="footer">
966
- <slot name="footer"></slot>
1097
+ <footer class=${footerClass} part="footer">
1098
+ <slot name="footer" @slotchange=${this.onSlotChange}></slot>
967
1099
  </footer>
968
1100
  </div>
969
1101
  `;
970
1102
  }
1103
+ /**
1104
+ * Re-render when a named slot's assignment changes so a footer/header added
1105
+ * after first paint updates the empty-region class. The initial render reads
1106
+ * children synchronously (no empty-then-filled flash).
1107
+ */
1108
+ onSlotChange = () => {
1109
+ this.requestUpdate();
1110
+ };
971
1111
  lightDomSlotFilled(slot) {
972
1112
  for (const child of this.children) if (child.getAttribute("slot") === slot) return true;
973
1113
  return false;
@@ -1248,6 +1388,7 @@ const zlPasskeyManifest = {
1248
1388
  consumes: {},
1249
1389
  attrs: [
1250
1390
  "ceremony",
1391
+ "method",
1251
1392
  "challenge-id",
1252
1393
  "options",
1253
1394
  "manual"
@@ -1287,11 +1428,11 @@ let ZlPill = class ZlPill extends LitElement {
1287
1428
  set ariaLabel(value) {
1288
1429
  this.#_ariaLabel_accessor_storage = value;
1289
1430
  }
1290
- surfaceClasses() {
1291
- return ["zr-pill", this.tone !== "neutral" ? `zr-pill--${this.tone}` : ""].filter(Boolean).join(" ");
1292
- }
1293
1431
  render() {
1294
- const classes = this.surfaceClasses();
1432
+ const classes = classMap({
1433
+ "zr-pill": true,
1434
+ [`zr-pill--${this.tone}`]: this.tone !== "neutral"
1435
+ });
1295
1436
  if (this.href) return html`<a
1296
1437
  class=${classes}
1297
1438
  part="pill"
@@ -1314,10 +1455,10 @@ const zlPillManifest = {
1314
1455
  "aria-label"
1315
1456
  ],
1316
1457
  parts: ["pill"],
1317
- slots: [],
1458
+ slots: [""],
1318
1459
  events: []
1319
1460
  };
1320
1461
  //#endregion
1321
- export { __decorate as _, ZlPageShell as a, t as b, zlFieldManifest as c, ZlButton as d, zlButtonManifest as f, zlIconManifest as g, ZlIcon as h, zlPasskeyManifest as i, ZlCard as l, zlAlertManifest as m, zlPillManifest as n, zlPageShellManifest as o, ZlAlert as p, ZlPasskey as r, ZlField as s, ZlPill as t, zlCardManifest as u, focusVisibleStyles as v, baseHostStyles as y };
1462
+ export { __decorate as _, ZlPageShell as a, t as b, zlFieldManifest as c, ZlButton as d, zlButtonManifest as f, zlIconManifest as g, ZlIcon as h, zlPasskeyManifest as i, ZlCard as l, zlAlertManifest as m, zlPillManifest as n, zlPageShellManifest as o, ZlAlert as p, ZlPasskey as r, ZlField as s, ZlPill as t, zlCardManifest as u, focusVisibleStyles as v, emit as x, baseHostStyles as y };
1322
1463
 
1323
- //# sourceMappingURL=atoms-B9yd0c-i.mjs.map
1464
+ //# sourceMappingURL=atoms-BaayzEsr.mjs.map