@reliability-design/web 1.4.2 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -76,6 +76,7 @@ __export(index_exports, {
76
76
  RelTab: () => RelTab,
77
77
  RelTabItem: () => RelTabItem,
78
78
  RelTextfield: () => RelTextfield,
79
+ RelTimePicker: () => RelTimePicker,
79
80
  RelToast: () => RelToast,
80
81
  RelTooltip: () => RelTooltip,
81
82
  RelTopbar: () => RelTopbar,
@@ -760,6 +761,7 @@ var RelTextfield = class extends import_lit3.LitElement {
760
761
  this.internalState = "default";
761
762
  this._wasError = false;
762
763
  this.uniqueId = `textfield-${Math.random().toString(36).slice(2)}`;
764
+ this._warnedNoName = false;
763
765
  }
764
766
  get isDisabled() {
765
767
  return this.disabled || this.state === "disabled";
@@ -775,6 +777,15 @@ var RelTextfield = class extends import_lit3.LitElement {
775
777
  get helper() {
776
778
  return this.helperText ?? this.supportingText;
777
779
  }
780
+ /** labelStyle supersedes the deprecated floatingLabel boolean. */
781
+ get resolvedLabelStyle() {
782
+ if (this.labelStyle) return this.labelStyle;
783
+ return this.floatingLabel ? "floating" : "default";
784
+ }
785
+ /** True when no visible label renders and the input needs an ARIA name. */
786
+ get labelHidden() {
787
+ return this.resolvedLabelStyle === "none";
788
+ }
778
789
  connectedCallback() {
779
790
  super.connectedCallback();
780
791
  const leftIcon = this.getAttribute("lefticon") || this.getAttribute("leftIcon");
@@ -782,6 +793,20 @@ var RelTextfield = class extends import_lit3.LitElement {
782
793
  const rightIcon = this.getAttribute("righticon") || this.getAttribute("rightIcon");
783
794
  if (rightIcon) this.rightIcon = rightIcon;
784
795
  }
796
+ willUpdate(changed) {
797
+ if (changed.has("labelStyle") && this.labelStyle) {
798
+ this.floatingLabel = this.labelStyle === "floating";
799
+ }
800
+ }
801
+ updated() {
802
+ if (this._warnedNoName || !this.labelHidden) return;
803
+ if (this.fieldAriaLabel || this.fieldAriaLabelledby || this.getAttribute("aria-label")) return;
804
+ this._warnedNoName = true;
805
+ console.warn(
806
+ '<rel-textfield label-style="none"> has no accessible name. Set `field-aria-label` or `field-aria-labelledby` \u2014 a placeholder is not a valid naming mechanism.',
807
+ this
808
+ );
809
+ }
785
810
  /** Focuses the inner input/textarea (the host itself is not focusable). */
786
811
  focus(options) {
787
812
  this.renderRoot.querySelector("input, textarea")?.focus(options);
@@ -849,15 +874,20 @@ var RelTextfield = class extends import_lit3.LitElement {
849
874
  !this.multiline && leadingIcon ? "has-left-icon" : "",
850
875
  !this.multiline && this.rightIcon && this.variant !== "legend" ? "has-right-icon" : ""
851
876
  ].filter(Boolean).join(" ");
877
+ const labelStyle = this.resolvedLabelStyle;
878
+ const labelHidden = labelStyle === "none";
852
879
  const labelTemplate = (extraClass = "") => {
853
- if (!this.label) return "";
880
+ if (!this.label || labelHidden) return "";
854
881
  return import_lit3.html`<label
855
882
  part="label"
856
883
  class="textfield-label${extraClass}"
857
884
  for="${inputId}"
858
885
  >${this.label}${this.required ? import_lit3.html`<span class="required-mark" aria-hidden="true">*</span>` : ""}</label>`;
859
886
  };
860
- const ariaLabelledby = this.variant === "legend" && this.label ? legendId : void 0;
887
+ const legendLabelledby = this.variant === "legend" && this.label && !labelHidden ? legendId : void 0;
888
+ const ariaLabelledby = this.fieldAriaLabelledby ?? legendLabelledby;
889
+ const hasVisibleLabel = !labelHidden && !!this.label;
890
+ const ariaLabel = !hasVisibleLabel && !ariaLabelledby ? this.fieldAriaLabel : void 0;
861
891
  const inputTemplate = this.multiline ? import_lit3.html`<textarea part="input"
862
892
  id="${inputId}"
863
893
  class="${inputClasses}"
@@ -871,6 +901,7 @@ var RelTextfield = class extends import_lit3.LitElement {
871
901
  ?required="${this.required}"
872
902
  aria-invalid="${isError}"
873
903
  aria-required="${this.required}"
904
+ aria-label="${ariaLabel ?? import_lit3.nothing}"
874
905
  aria-labelledby="${ariaLabelledby ?? import_lit3.nothing}"
875
906
  aria-describedby="${describedById ?? import_lit3.nothing}"
876
907
  @focus="${this.handleFocus}"
@@ -889,6 +920,7 @@ var RelTextfield = class extends import_lit3.LitElement {
889
920
  ?required="${this.required}"
890
921
  aria-invalid="${isError}"
891
922
  aria-required="${this.required}"
923
+ aria-label="${ariaLabel ?? import_lit3.nothing}"
892
924
  aria-labelledby="${ariaLabelledby ?? import_lit3.nothing}"
893
925
  aria-describedby="${describedById ?? import_lit3.nothing}"
894
926
  @focus="${this.handleFocus}"
@@ -910,7 +942,7 @@ var RelTextfield = class extends import_lit3.LitElement {
910
942
  const fieldsetClass = ["field-fieldset", this.multiline ? "multiline" : ""].filter(Boolean).join(" ");
911
943
  return import_lit3.html`
912
944
  <div class="${wrapperClasses}">
913
- <fieldset part="control" class="${fieldsetClass}"><legend class="field-legend" id="${legendId}">${this.label ?? ""}${this.required ? import_lit3.html`<span class="required-mark" aria-hidden="true">*</span>` : ""}</legend>
945
+ <fieldset part="control" class="${fieldsetClass}"><legend class="field-legend" id="${legendId}">${labelHidden ? "" : this.label ?? ""}${this.required && !labelHidden ? import_lit3.html`<span class="required-mark" aria-hidden="true">*</span>` : ""}</legend>
914
946
  ${!this.multiline ? leadingIconTemplate : ""}
915
947
  ${inputTemplate}
916
948
  </fieldset>
@@ -920,10 +952,10 @@ var RelTextfield = class extends import_lit3.LitElement {
920
952
  }
921
953
  return import_lit3.html`
922
954
  <div class="${wrapperClasses}">
923
- ${!this.floatingLabel ? labelTemplate() : ""}
955
+ ${labelHidden ? import_lit3.html`<div class="label-reserve" aria-hidden="true"></div>` : labelStyle !== "floating" ? labelTemplate() : ""}
924
956
 
925
957
  <div part="control" class="${["textfield-container", this.isDisabled ? "disabled" : "", this.multiline ? "multiline" : ""].filter(Boolean).join(" ")}">
926
- ${this.floatingLabel ? labelTemplate(leadingIcon && !this.multiline ? " has-left-icon" : "") : ""}
958
+ ${labelStyle === "floating" ? labelTemplate(leadingIcon && !this.multiline ? " has-left-icon" : "") : ""}
927
959
  ${!this.multiline ? leadingIconTemplate : ""}
928
960
 
929
961
  ${inputTemplate}
@@ -982,6 +1014,22 @@ RelTextfield.styles = import_lit3.css`
982
1014
  margin-left: 2px;
983
1015
  }
984
1016
 
1017
+ /* ── labelStyle="none" ──
1018
+ No label renders. An empty spacer holds the label row's full height so the
1019
+ input box still bottom-aligns with labelled siblings in a form row.
1020
+ The reserve covers label line-height + the wrapper gap, and the negative
1021
+ margin cancels the flex gap that would otherwise sit below it — so
1022
+ --rel-field-label-reserve: 0 collapses the row to genuinely zero
1023
+ (toolbars, table cells), not just to the leftover gap. */
1024
+ .label-reserve {
1025
+ flex: none;
1026
+ height: var(
1027
+ --rel-field-label-reserve,
1028
+ calc(var(--rel-body-sm-medium-line-height) + var(--rel-spacing-2xs))
1029
+ );
1030
+ margin-bottom: calc(-1 * var(--rel-spacing-2xs));
1031
+ }
1032
+
985
1033
  /* Floating label variant */
986
1034
  :host([floatinglabel]) .textfield-wrapper {
987
1035
  gap: 0;
@@ -1358,6 +1406,12 @@ RelTextfield.styles = import_lit3.css`
1358
1406
  box-sizing: border-box;
1359
1407
  }
1360
1408
 
1409
+ /* labelStyle="none" + legend: nothing to seat in the notch, so drop the
1410
+ legend entirely and let the top border run continuous. */
1411
+ :host([label-style="none"][variant="legend"]) .field-legend {
1412
+ display: none;
1413
+ }
1414
+
1361
1415
  /* Prefix icon (legend): vertically centered; input inset via has-left-icon */
1362
1416
  :host([variant="legend"]) .icon.left {
1363
1417
  top: 50%;
@@ -1473,9 +1527,18 @@ __decorateClass([
1473
1527
  __decorateClass([
1474
1528
  (0, import_decorators3.property)({ type: String })
1475
1529
  ], RelTextfield.prototype, "size", 2);
1530
+ __decorateClass([
1531
+ (0, import_decorators3.property)({ type: String, attribute: "label-style", reflect: true })
1532
+ ], RelTextfield.prototype, "labelStyle", 2);
1476
1533
  __decorateClass([
1477
1534
  (0, import_decorators3.property)({ type: Boolean, reflect: true })
1478
1535
  ], RelTextfield.prototype, "floatingLabel", 2);
1536
+ __decorateClass([
1537
+ (0, import_decorators3.property)({ type: String, attribute: "field-aria-label" })
1538
+ ], RelTextfield.prototype, "fieldAriaLabel", 2);
1539
+ __decorateClass([
1540
+ (0, import_decorators3.property)({ type: String, attribute: "field-aria-labelledby" })
1541
+ ], RelTextfield.prototype, "fieldAriaLabelledby", 2);
1479
1542
  __decorateClass([
1480
1543
  (0, import_decorators3.property)({ type: String, reflect: true })
1481
1544
  ], RelTextfield.prototype, "variant", 2);
@@ -1588,6 +1651,11 @@ var RelAutocomplete = class extends import_lit4.LitElement {
1588
1651
  this.panelStyle = `top:${top}px;left:${left}px;width:${t.width}px;`;
1589
1652
  };
1590
1653
  }
1654
+ /** Name used for the suggestion panel — the visible label, or fieldAriaLabel
1655
+ * once labelStyle="none" hides it. Mirrors rel-textfield's own resolution. */
1656
+ get accessibleName() {
1657
+ return (this.labelStyle === "none" ? this.fieldAriaLabel : this.label) || "";
1658
+ }
1591
1659
  disconnectedCallback() {
1592
1660
  super.disconnectedCallback();
1593
1661
  this.removeGlobalListeners();
@@ -1692,17 +1760,17 @@ var RelAutocomplete = class extends import_lit4.LitElement {
1692
1760
  this.syncPanel();
1693
1761
  }
1694
1762
  }
1695
- async runSearch(query10) {
1763
+ async runSearch(query11) {
1696
1764
  const seq = ++this.searchSeq;
1697
1765
  try {
1698
- const results = await this.searchFn(query10);
1766
+ const results = await this.searchFn(query11);
1699
1767
  if (seq !== this.searchSeq) return;
1700
1768
  this.remoteItems = results ?? [];
1701
1769
  } catch (err) {
1702
1770
  if (seq !== this.searchSeq) return;
1703
1771
  this.remoteItems = [];
1704
1772
  this.dispatchEvent(
1705
- new CustomEvent("rel-search-error", { detail: { query: query10, error: err }, bubbles: true, composed: true })
1773
+ new CustomEvent("rel-search-error", { detail: { query: query11, error: err }, bubbles: true, composed: true })
1706
1774
  );
1707
1775
  } finally {
1708
1776
  if (seq === this.searchSeq) {
@@ -1848,7 +1916,10 @@ var RelAutocomplete = class extends import_lit4.LitElement {
1848
1916
  .value="${this.inputText}"
1849
1917
  .size="${this.size}"
1850
1918
  .variant="${this.variant}"
1919
+ .labelStyle="${this.labelStyle}"
1851
1920
  .floatingLabel="${this.floatingLabel}"
1921
+ .fieldAriaLabel="${this.fieldAriaLabel}"
1922
+ .fieldAriaLabelledby="${this.fieldAriaLabelledby}"
1852
1923
  .prefixIcon="${this.prefixIcon}"
1853
1924
  .disabled="${this.disabled}"
1854
1925
  .readonly="${this.readonly}"
@@ -1870,7 +1941,7 @@ var RelAutocomplete = class extends import_lit4.LitElement {
1870
1941
  part="panel list"
1871
1942
  class="ac-panel"
1872
1943
  role="listbox"
1873
- aria-label="${this.label || "Suggestions"}"
1944
+ aria-label="${this.accessibleName || "Suggestions"}"
1874
1945
  style="${this.panelStyle}"
1875
1946
  ?data-open="${this.open}"
1876
1947
  >
@@ -2049,9 +2120,18 @@ __decorateClass([
2049
2120
  __decorateClass([
2050
2121
  (0, import_decorators4.property)({ type: String })
2051
2122
  ], RelAutocomplete.prototype, "variant", 2);
2123
+ __decorateClass([
2124
+ (0, import_decorators4.property)({ type: String, attribute: "label-style", reflect: true })
2125
+ ], RelAutocomplete.prototype, "labelStyle", 2);
2052
2126
  __decorateClass([
2053
2127
  (0, import_decorators4.property)({ type: Boolean, attribute: "floating-label" })
2054
2128
  ], RelAutocomplete.prototype, "floatingLabel", 2);
2129
+ __decorateClass([
2130
+ (0, import_decorators4.property)({ type: String, attribute: "field-aria-label" })
2131
+ ], RelAutocomplete.prototype, "fieldAriaLabel", 2);
2132
+ __decorateClass([
2133
+ (0, import_decorators4.property)({ type: String, attribute: "field-aria-labelledby" })
2134
+ ], RelAutocomplete.prototype, "fieldAriaLabelledby", 2);
2055
2135
  __decorateClass([
2056
2136
  (0, import_decorators4.property)({ type: String, attribute: "prefix-icon" })
2057
2137
  ], RelAutocomplete.prototype, "prefixIcon", 2);
@@ -2763,8 +2843,8 @@ RelButton.styles = import_lit8.css`
2763
2843
  pointer-events:none on the HOST would make it transparent to the
2764
2844
  pointer and suppress the cursor entirely. */
2765
2845
  cursor: not-allowed;
2766
- /* The disabled tokens are full-contrast pairs (light: #0B0B0B on
2767
- #C2C2C2, dark: #FFF on #404040), so on their own they render a
2846
+ /* The disabled tokens are full-contrast pairs (light: near-black on
2847
+ gray-300, dark: white on gray-700), so on their own they render a
2768
2848
  crisp button that reads as enabled. Dulling happens here instead —
2769
2849
  same opacity mechanism the rest of the library uses. */
2770
2850
  opacity: 0.5;
@@ -8309,6 +8389,8 @@ var RelRadio = class extends import_lit23.LitElement {
8309
8389
  super(...arguments);
8310
8390
  this.options = [];
8311
8391
  this.name = "radio-group";
8392
+ this.orientation = "vertical";
8393
+ this.size = "medium";
8312
8394
  this.selectedValue = null;
8313
8395
  this.disabled = false;
8314
8396
  this.error = false;
@@ -8374,7 +8456,12 @@ var RelRadio = class extends import_lit23.LitElement {
8374
8456
  }
8375
8457
  render() {
8376
8458
  return import_lit23.html`
8377
- <div part="base" class="rel-radio-group">
8459
+ <div
8460
+ part="base"
8461
+ class="rel-radio-group"
8462
+ role="radiogroup"
8463
+ aria-orientation="${this.orientation}"
8464
+ >
8378
8465
  ${this.options.map((o) => this.renderOption(o))}
8379
8466
  </div>
8380
8467
  ${this.error && this.errorMessage ? import_lit23.html`<div class="error-message">${this.errorMessage}</div>` : ""}
@@ -8395,6 +8482,15 @@ RelRadio.styles = import_lit23.css`
8395
8482
  gap: var(--rel-spacing-xs);
8396
8483
  }
8397
8484
 
8485
+ /* Horizontal orientation — options flow in a wrapping row. Wider column
8486
+ gap than the vertical rhythm so adjacent option labels read as separate
8487
+ choices; row gap keeps the vertical value for wrapped lines. */
8488
+ :host([orientation="horizontal"]) .rel-radio-group {
8489
+ flex-direction: row;
8490
+ flex-wrap: wrap;
8491
+ gap: var(--rel-spacing-xs) var(--rel-spacing-xl);
8492
+ }
8493
+
8398
8494
  .rel-radio-option {
8399
8495
  display: inline-flex;
8400
8496
  flex-direction: column;
@@ -8497,6 +8593,34 @@ RelRadio.styles = import_lit23.css`
8497
8593
 
8498
8594
  }
8499
8595
 
8596
+ /* Size variant (medium is the base scale above). Supporting-text indent =
8597
+ circle width + the radio-main gap, so it stays aligned under the label. */
8598
+ :host([size="small"]) .radio-custom {
8599
+ width: 16px;
8600
+ height: 16px;
8601
+ }
8602
+
8603
+ :host([size="small"]) input:checked + .radio-custom::after {
8604
+ inset: 3px;
8605
+ }
8606
+
8607
+ :host([size="small"]) .radio-label {
8608
+ font-family: var(--rel-body-md-regular-font-family);
8609
+ font-weight: var(--rel-body-md-regular-font-weight);
8610
+ font-size: var(--rel-body-md-regular-font-size);
8611
+ line-height: var(--rel-body-md-regular-line-height);
8612
+ letter-spacing: var(--rel-body-md-regular-letter-spacing);
8613
+ }
8614
+
8615
+ :host([size="small"]) .radio-supporting {
8616
+ margin-left: 24px;
8617
+ font-family: var(--rel-body-xs-regular-font-family);
8618
+ font-weight: var(--rel-body-xs-regular-font-weight);
8619
+ font-size: var(--rel-body-xs-regular-font-size);
8620
+ line-height: var(--rel-body-xs-regular-line-height);
8621
+ letter-spacing: var(--rel-body-xs-regular-letter-spacing);
8622
+ }
8623
+
8500
8624
  /* Error state (Figma State=Error, both Is Checked values) */
8501
8625
  .rel-radio-option.error-unchecked .radio-custom,
8502
8626
  .rel-radio-option.error-checked .radio-custom {
@@ -8540,6 +8664,12 @@ __decorateClass([
8540
8664
  __decorateClass([
8541
8665
  (0, import_decorators23.property)({ type: String })
8542
8666
  ], RelRadio.prototype, "name", 2);
8667
+ __decorateClass([
8668
+ (0, import_decorators23.property)({ type: String, reflect: true })
8669
+ ], RelRadio.prototype, "orientation", 2);
8670
+ __decorateClass([
8671
+ (0, import_decorators23.property)({ type: String, reflect: true })
8672
+ ], RelRadio.prototype, "size", 2);
8543
8673
  __decorateClass([
8544
8674
  (0, import_decorators23.property)({ type: String, reflect: true })
8545
8675
  ], RelRadio.prototype, "selectedValue", 2);
@@ -13139,6 +13269,7 @@ var RelSelect = class extends import_lit46.LitElement {
13139
13269
  this.internalState = "default";
13140
13270
  this.visibleChipCount = Infinity;
13141
13271
  this.uniqueId = `select-${Math.random().toString(36).slice(2)}`;
13272
+ this._warnedNoName = false;
13142
13273
  this.onOutsidePointerDown = (e) => {
13143
13274
  if (!this.open) return;
13144
13275
  const path = e.composedPath();
@@ -13197,6 +13328,13 @@ var RelSelect = class extends import_lit46.LitElement {
13197
13328
  }
13198
13329
  }
13199
13330
  updated(changed) {
13331
+ if (!this._warnedNoName && this.labelStyle === "none" && !this.fieldAriaLabel && !this.fieldAriaLabelledby && !this.getAttribute("aria-label")) {
13332
+ this._warnedNoName = true;
13333
+ console.warn(
13334
+ '<rel-select label-style="none"> has no accessible name. Set `field-aria-label` or `field-aria-labelledby` \u2014 a placeholder is not a valid naming mechanism.',
13335
+ this
13336
+ );
13337
+ }
13200
13338
  if (changed.has("selectedValues") || changed.has("options") || changed.has("multiple") || changed.has("size")) {
13201
13339
  requestAnimationFrame(() => this.computeVisibleChips());
13202
13340
  }
@@ -13445,7 +13583,9 @@ var RelSelect = class extends import_lit46.LitElement {
13445
13583
  const opts = this.normalizedOptions;
13446
13584
  const filtered = this.filteredOptions;
13447
13585
  const isDisabled = this.state === "disabled";
13586
+ const labelHidden = this.labelStyle === "none";
13448
13587
  const showFloatingChrome = this.labelStyle === "floating" && !!this.label;
13588
+ const accessibleName = (labelHidden ? this.fieldAriaLabel : this.label) || "";
13449
13589
  const wrapperClasses = [
13450
13590
  "select-wrapper",
13451
13591
  this.size,
@@ -13461,7 +13601,7 @@ var RelSelect = class extends import_lit46.LitElement {
13461
13601
  const selectedSingle = opts.find((o) => o.value === this.selected);
13462
13602
  return import_lit46.html`
13463
13603
  <div class="${wrapperClasses}">
13464
- ${!showFloatingChrome && this.label ? import_lit46.html`<label part="label" class="select-label" for="${this.uniqueId}">${this.label}</label>` : ""}
13604
+ ${labelHidden ? import_lit46.html`<div class="label-reserve" aria-hidden="true"></div>` : !showFloatingChrome && this.label ? import_lit46.html`<label part="label" class="select-label" for="${this.uniqueId}">${this.label}</label>` : ""}
13465
13605
 
13466
13606
  <div class="select-container">
13467
13607
  ${showFloatingChrome ? import_lit46.html`<span class="floating-label${this.leftIcon ? " has-left-icon" : ""}"
@@ -13478,7 +13618,8 @@ var RelSelect = class extends import_lit46.LitElement {
13478
13618
  aria-controls="${listboxId}"
13479
13619
  aria-activedescendant="${activeOptionId}"
13480
13620
  aria-invalid="${this.state === "error"}"
13481
- aria-label="${this.label || this.placeholder}"
13621
+ aria-label="${this.fieldAriaLabelledby ? import_lit46.nothing : accessibleName || this.placeholder}"
13622
+ aria-labelledby="${this.fieldAriaLabelledby ?? import_lit46.nothing}"
13482
13623
  ?disabled="${isDisabled}"
13483
13624
  @click="${this.onTriggerClick}"
13484
13625
  @keydown="${this.onTriggerKeyDown}"
@@ -13515,7 +13656,7 @@ var RelSelect = class extends import_lit46.LitElement {
13515
13656
  part="panel list" class="select-listbox"
13516
13657
  role="listbox"
13517
13658
  aria-multiselectable="${this.multiple}"
13518
- aria-label="${this.label || "Options"}"
13659
+ aria-label="${accessibleName || "Options"}"
13519
13660
  style="${this.panelStyle}"
13520
13661
  ?data-open="${this.open}"
13521
13662
  >
@@ -13644,6 +13785,22 @@ RelSelect.styles = import_lit46.css`
13644
13785
 
13645
13786
  }
13646
13787
 
13788
+ /* ── labelStyle="none" ──
13789
+ No label renders. An empty spacer holds the label row's full height so the
13790
+ trigger still bottom-aligns with labelled siblings in a form row.
13791
+ The reserve covers label line-height + the wrapper gap, and the negative
13792
+ margin cancels the flex gap that would otherwise sit below it — so
13793
+ --rel-field-label-reserve: 0 collapses the row to genuinely zero
13794
+ (toolbars, table cells), not just to the leftover gap. */
13795
+ .label-reserve {
13796
+ flex: none;
13797
+ height: var(
13798
+ --rel-field-label-reserve,
13799
+ calc(var(--rel-body-sm-regular-line-height) + var(--rel-spacing-2xs))
13800
+ );
13801
+ margin-bottom: calc(-1 * var(--rel-spacing-2xs));
13802
+ }
13803
+
13647
13804
  /* Error only colors the border/focus ring and the supporting text below
13648
13805
  the field — label, floating label, placeholder, and icons stay normal. */
13649
13806
 
@@ -14037,8 +14194,14 @@ __decorateClass([
14037
14194
  (0, import_decorators46.property)({ type: String })
14038
14195
  ], RelSelect.prototype, "label", 2);
14039
14196
  __decorateClass([
14040
- (0, import_decorators46.property)({ type: String, attribute: "label-style" })
14197
+ (0, import_decorators46.property)({ type: String, attribute: "label-style", reflect: true })
14041
14198
  ], RelSelect.prototype, "labelStyle", 2);
14199
+ __decorateClass([
14200
+ (0, import_decorators46.property)({ type: String, attribute: "field-aria-label" })
14201
+ ], RelSelect.prototype, "fieldAriaLabel", 2);
14202
+ __decorateClass([
14203
+ (0, import_decorators46.property)({ type: String, attribute: "field-aria-labelledby" })
14204
+ ], RelSelect.prototype, "fieldAriaLabelledby", 2);
14042
14205
  __decorateClass([
14043
14206
  (0, import_decorators46.property)({ type: Array })
14044
14207
  ], RelSelect.prototype, "options", 2);
@@ -16637,89 +16800,1031 @@ RelTab = __decorateClass([
16637
16800
  (0, import_decorators53.customElement)("rel-tab")
16638
16801
  ], RelTab);
16639
16802
 
16640
- // src/components/rel-toast/rel-toast.ts
16803
+ // src/components/rel-time-picker/rel-time-picker.ts
16641
16804
  var import_lit54 = require("lit");
16642
16805
  var import_decorators54 = require("lit/decorators.js");
16643
- var RelToast = class extends import_lit54.LitElement {
16806
+ var import_rel_icon16 = require("@reliability-design/icons/rel-icon");
16807
+ var RelTimePicker = class extends import_lit54.LitElement {
16644
16808
  constructor() {
16645
16809
  super(...arguments);
16646
- this.message = "";
16647
- this.type = "default";
16648
- this.duration = 4e3;
16649
- this.show = false;
16650
- this.visible = false;
16651
- this._dismissTimer = null;
16652
- }
16653
- willUpdate(changed) {
16654
- if (!changed.has("show")) return;
16655
- if (this.show) {
16656
- this.visible = true;
16657
- if (this._dismissTimer) clearTimeout(this._dismissTimer);
16658
- if (this.duration > 0) {
16659
- this._dismissTimer = setTimeout(() => this.close(), this.duration);
16810
+ this.value = null;
16811
+ this.placeholder = "Select time";
16812
+ this.label = null;
16813
+ this.disabled = false;
16814
+ this.required = false;
16815
+ this.readonly = false;
16816
+ this.format = "12h";
16817
+ this.minuteStep = 1;
16818
+ this.minTime = null;
16819
+ this.maxTime = null;
16820
+ this.open = false;
16821
+ this.clearable = false;
16822
+ this.error = false;
16823
+ this.invalid = false;
16824
+ this.size = "medium";
16825
+ this.variant = "outlined";
16826
+ this.fullWidth = false;
16827
+ this.draftHour = null;
16828
+ this.draftMinute = null;
16829
+ this.handleClickOutside = (e) => {
16830
+ if (!this.open) return;
16831
+ const path = e.composedPath();
16832
+ if (!path.includes(this)) {
16833
+ this.cancelPopover();
16660
16834
  }
16661
- } else {
16662
- this.visible = false;
16663
- if (this._dismissTimer) {
16664
- clearTimeout(this._dismissTimer);
16665
- this._dismissTimer = null;
16835
+ };
16836
+ this.handleEscapeKey = (e) => {
16837
+ if (e.key === "Escape" && this.open) {
16838
+ this.cancelPopover();
16666
16839
  }
16667
- }
16840
+ };
16841
+ }
16842
+ connectedCallback() {
16843
+ super.connectedCallback();
16844
+ document.addEventListener("click", this.handleClickOutside);
16845
+ document.addEventListener("keydown", this.handleEscapeKey);
16668
16846
  }
16669
16847
  disconnectedCallback() {
16670
16848
  super.disconnectedCallback();
16671
- if (this._dismissTimer) clearTimeout(this._dismissTimer);
16849
+ document.removeEventListener("click", this.handleClickOutside);
16850
+ document.removeEventListener("keydown", this.handleEscapeKey);
16672
16851
  }
16673
- open() {
16674
- this.show = true;
16852
+ updated(changedProperties) {
16853
+ if (changedProperties.has("open") && this.open) {
16854
+ this.resetDraftFromValue();
16855
+ setTimeout(() => {
16856
+ this.scrollColumnsToSelection();
16857
+ const target = this.columnsElement?.querySelector(
16858
+ ".option-button.selected:not(:disabled)"
16859
+ ) ?? this.columnsElement?.querySelector(
16860
+ ".option-button:not(:disabled)"
16861
+ );
16862
+ target?.focus();
16863
+ }, 0);
16864
+ }
16675
16865
  }
16676
- close() {
16677
- this.show = false;
16678
- this.visible = false;
16679
- if (this._dismissTimer) {
16680
- clearTimeout(this._dismissTimer);
16681
- this._dismissTimer = null;
16866
+ // ── Parsing / formatting ──
16867
+ parseTime(time) {
16868
+ if (!time) return null;
16869
+ const match = time.match(/^(\d{1,2}):(\d{2})$/);
16870
+ if (!match) return null;
16871
+ const hour = parseInt(match[1], 10);
16872
+ const minute = parseInt(match[2], 10);
16873
+ if (hour > 23 || minute > 59) return null;
16874
+ return { hour, minute };
16875
+ }
16876
+ formatValue(hour, minute) {
16877
+ return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
16878
+ }
16879
+ formatDisplay(hour, minute) {
16880
+ const mm = String(minute).padStart(2, "0");
16881
+ if (this.format === "24h") {
16882
+ return `${String(hour).padStart(2, "0")}:${mm}`;
16883
+ }
16884
+ const period = hour < 12 ? "AM" : "PM";
16885
+ const hour12 = hour % 12 === 0 ? 12 : hour % 12;
16886
+ return `${hour12}:${mm} ${period}`;
16887
+ }
16888
+ toMinutes(hour, minute) {
16889
+ return hour * 60 + minute;
16890
+ }
16891
+ get minuteStepSafe() {
16892
+ const step = Math.floor(this.minuteStep);
16893
+ return step >= 1 && step <= 60 ? step : 1;
16894
+ }
16895
+ get minBoundMinutes() {
16896
+ const parsed = this.parseTime(this.minTime);
16897
+ return parsed ? this.toMinutes(parsed.hour, parsed.minute) : 0;
16898
+ }
16899
+ get maxBoundMinutes() {
16900
+ const parsed = this.parseTime(this.maxTime);
16901
+ return parsed ? this.toMinutes(parsed.hour, parsed.minute) : 23 * 60 + 59;
16902
+ }
16903
+ isTimeInRange(hour, minute) {
16904
+ const total = this.toMinutes(hour, minute);
16905
+ return total >= this.minBoundMinutes && total <= this.maxBoundMinutes;
16906
+ }
16907
+ /** Minutes shown in the minutes column (respecting minuteStep). */
16908
+ getMinuteOptions() {
16909
+ const minutes = [];
16910
+ for (let m = 0; m < 60; m += this.minuteStepSafe) {
16911
+ minutes.push(m);
16912
+ }
16913
+ return minutes;
16914
+ }
16915
+ /** An hour is enabled if at least one of its step minutes is in range. */
16916
+ isHourEnabled(hour) {
16917
+ return this.getMinuteOptions().some((m) => this.isTimeInRange(hour, m));
16918
+ }
16919
+ isPeriodEnabled(period) {
16920
+ const start = period === "AM" ? 0 : 12;
16921
+ for (let h = start; h < start + 12; h++) {
16922
+ if (this.isHourEnabled(h)) return true;
16923
+ }
16924
+ return false;
16925
+ }
16926
+ /** Hour column entries: display label + the 0–23 hour it maps to. */
16927
+ getHourOptions() {
16928
+ if (this.format === "24h") {
16929
+ return Array.from({ length: 24 }, (_, h) => ({
16930
+ label: String(h).padStart(2, "0"),
16931
+ hour24: h
16932
+ }));
16933
+ }
16934
+ const period = this.draftPeriod ?? "AM";
16935
+ const base = period === "AM" ? 0 : 12;
16936
+ return Array.from({ length: 12 }, (_, i) => ({
16937
+ label: i === 0 ? "12" : String(i).padStart(2, "0"),
16938
+ hour24: base + i
16939
+ }));
16940
+ }
16941
+ get draftPeriod() {
16942
+ if (this.draftHour === null) return null;
16943
+ return this.draftHour < 12 ? "AM" : "PM";
16944
+ }
16945
+ resetDraftFromValue() {
16946
+ const parsed = this.parseTime(this.value);
16947
+ this.draftHour = parsed ? parsed.hour : null;
16948
+ this.draftMinute = parsed ? parsed.minute : null;
16949
+ }
16950
+ /** Snap the draft minute to the nearest valid step minute for the hour. */
16951
+ clampDraftToRange() {
16952
+ if (this.draftHour === null || this.draftMinute === null) return;
16953
+ if (this.isTimeInRange(this.draftHour, this.draftMinute)) return;
16954
+ const hour = this.draftHour;
16955
+ const valid = this.getMinuteOptions().filter((m) => this.isTimeInRange(hour, m));
16956
+ if (valid.length === 0) {
16957
+ this.draftMinute = null;
16958
+ return;
16682
16959
  }
16960
+ const current = this.draftMinute;
16961
+ this.draftMinute = valid.reduce(
16962
+ (best, m) => Math.abs(m - current) < Math.abs(best - current) ? m : best
16963
+ );
16964
+ }
16965
+ // ── Open / close / commit ──
16966
+ toggleTimePopover() {
16967
+ if (this.disabled || this.readonly) return;
16968
+ this.open = !this.open;
16683
16969
  this.dispatchEvent(
16684
- new CustomEvent("dismissed", {
16970
+ new CustomEvent("rel-open-change", {
16971
+ detail: { open: this.open },
16685
16972
  bubbles: true,
16686
16973
  composed: true
16687
16974
  })
16688
16975
  );
16689
16976
  }
16690
- handleActionClick(event) {
16691
- event.stopPropagation();
16977
+ /** Close discarding the draft (Cancel / Escape / outside click). */
16978
+ cancelPopover() {
16979
+ this.open = false;
16980
+ this.triggerButton?.focus();
16692
16981
  this.dispatchEvent(
16693
- new CustomEvent("action", {
16982
+ new CustomEvent("rel-open-change", {
16983
+ detail: { open: false },
16694
16984
  bubbles: true,
16695
16985
  composed: true
16696
16986
  })
16697
16987
  );
16698
- this.close();
16699
16988
  }
16989
+ applySelection() {
16990
+ if (this.draftHour === null) return;
16991
+ const newValue = this.formatValue(this.draftHour, this.draftMinute ?? 0);
16992
+ this.value = newValue;
16993
+ this.dispatchEvent(
16994
+ new CustomEvent("rel-change", {
16995
+ detail: { value: newValue },
16996
+ bubbles: true,
16997
+ composed: true
16998
+ })
16999
+ );
17000
+ this.cancelPopover();
17001
+ }
17002
+ /** Set the draft to the current time, snapped to the minute step and range. */
17003
+ selectNow() {
17004
+ const now = /* @__PURE__ */ new Date();
17005
+ const step = this.minuteStepSafe;
17006
+ this.draftHour = now.getHours();
17007
+ this.draftMinute = Math.round(now.getMinutes() / step) * step;
17008
+ if (this.draftMinute >= 60) {
17009
+ this.draftMinute = 0;
17010
+ this.draftHour = (this.draftHour + 1) % 24;
17011
+ }
17012
+ if (!this.isHourEnabled(this.draftHour)) {
17013
+ const enabled = [];
17014
+ for (let h = 0; h < 24; h++) if (this.isHourEnabled(h)) enabled.push(h);
17015
+ if (enabled.length === 0) return;
17016
+ const currentHour = this.draftHour;
17017
+ this.draftHour = enabled.reduce(
17018
+ (best, h) => Math.abs(h - currentHour) < Math.abs(best - currentHour) ? h : best
17019
+ );
17020
+ }
17021
+ this.clampDraftToRange();
17022
+ this.scrollColumnsToSelection();
17023
+ }
17024
+ clearValue(e) {
17025
+ e.stopPropagation();
17026
+ this.value = null;
17027
+ this.draftHour = null;
17028
+ this.draftMinute = null;
17029
+ this.dispatchEvent(
17030
+ new CustomEvent("rel-change", {
17031
+ detail: { value: null },
17032
+ bubbles: true,
17033
+ composed: true
17034
+ })
17035
+ );
17036
+ }
17037
+ // ── Column selection ──
17038
+ selectHour(hour24) {
17039
+ if (!this.isHourEnabled(hour24)) return;
17040
+ this.draftHour = hour24;
17041
+ if (this.draftMinute === null) this.draftMinute = 0;
17042
+ this.clampDraftToRange();
17043
+ }
17044
+ selectMinute(minute) {
17045
+ if (this.draftHour === null) {
17046
+ for (let h = 0; h < 24; h++) {
17047
+ if (this.isHourEnabled(h)) {
17048
+ this.draftHour = h;
17049
+ break;
17050
+ }
17051
+ }
17052
+ if (this.draftHour === null) return;
17053
+ }
17054
+ if (!this.isTimeInRange(this.draftHour, minute)) return;
17055
+ this.draftMinute = minute;
17056
+ }
17057
+ selectPeriod(period) {
17058
+ if (!this.isPeriodEnabled(period)) return;
17059
+ const base = period === "AM" ? 0 : 12;
17060
+ const hour12 = this.draftHour === null ? 0 : this.draftHour % 12;
17061
+ this.draftHour = base + hour12;
17062
+ if (this.draftMinute === null) this.draftMinute = 0;
17063
+ if (!this.isHourEnabled(this.draftHour)) {
17064
+ const enabled = [];
17065
+ for (let h = base; h < base + 12; h++) if (this.isHourEnabled(h)) enabled.push(h);
17066
+ const currentHour = this.draftHour;
17067
+ this.draftHour = enabled.reduce(
17068
+ (best, h) => Math.abs(h - currentHour) < Math.abs(best - currentHour) ? h : best
17069
+ );
17070
+ }
17071
+ this.clampDraftToRange();
17072
+ this.scrollColumnsToSelection();
17073
+ }
17074
+ scrollColumnsToSelection() {
17075
+ this.updateComplete.then(() => {
17076
+ this.columnsElement?.querySelectorAll(".option-button.selected").forEach((btn) => btn.scrollIntoView({ block: "center" }));
17077
+ });
17078
+ }
17079
+ // ── Keyboard ──
17080
+ handleTriggerKeydown(e) {
17081
+ if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
17082
+ e.preventDefault();
17083
+ if (!this.open) {
17084
+ this.toggleTimePopover();
17085
+ }
17086
+ }
17087
+ }
17088
+ /**
17089
+ * Column navigation: Up/Down move within the column (and select), Left/Right
17090
+ * jump between columns, Home/End go to the first/last option, Enter applies.
17091
+ */
17092
+ handleOptionKeydown(e, column) {
17093
+ const list = e.currentTarget.closest(".column-list");
17094
+ if (!list) return;
17095
+ const buttons = Array.from(
17096
+ list.querySelectorAll(".option-button:not(:disabled)")
17097
+ );
17098
+ const index = buttons.indexOf(e.currentTarget);
17099
+ let target;
17100
+ switch (e.key) {
17101
+ case "ArrowUp":
17102
+ e.preventDefault();
17103
+ target = buttons[Math.max(0, index - 1)];
17104
+ break;
17105
+ case "ArrowDown":
17106
+ e.preventDefault();
17107
+ target = buttons[Math.min(buttons.length - 1, index + 1)];
17108
+ break;
17109
+ case "Home":
17110
+ e.preventDefault();
17111
+ target = buttons[0];
17112
+ break;
17113
+ case "End":
17114
+ e.preventDefault();
17115
+ target = buttons[buttons.length - 1];
17116
+ break;
17117
+ case "ArrowLeft":
17118
+ case "ArrowRight": {
17119
+ e.preventDefault();
17120
+ this.focusAdjacentColumn(column, e.key === "ArrowRight" ? 1 : -1);
17121
+ return;
17122
+ }
17123
+ case "Enter":
17124
+ e.preventDefault();
17125
+ e.currentTarget.click();
17126
+ this.applySelection();
17127
+ return;
17128
+ default:
17129
+ return;
17130
+ }
17131
+ if (target && target !== buttons[index]) {
17132
+ target.click();
17133
+ target.focus();
17134
+ target.scrollIntoView({ block: "nearest" });
17135
+ }
17136
+ }
17137
+ focusAdjacentColumn(from, direction) {
17138
+ const order = this.format === "12h" ? ["hour", "minute", "period"] : ["hour", "minute"];
17139
+ const nextIndex = order.indexOf(from) + direction;
17140
+ if (nextIndex < 0 || nextIndex >= order.length) return;
17141
+ const lists = this.columnsElement?.querySelectorAll(".column-list");
17142
+ const list = lists?.[nextIndex];
17143
+ const target = list?.querySelector(".option-button.selected:not(:disabled)") ?? list?.querySelector(".option-button:not(:disabled)");
17144
+ target?.focus();
17145
+ target?.scrollIntoView({ block: "nearest" });
17146
+ }
17147
+ // ── Render ──
16700
17148
  render() {
17149
+ const isError = this.error || this.invalid;
17150
+ const belowText = isError && this.errorMessage ? this.errorMessage : this.helperText;
17151
+ const describedById = belowText ? "time-picker-desc" : void 0;
17152
+ const parsedValue = this.parseTime(this.value);
17153
+ const displayText = parsedValue ? this.formatDisplay(parsedValue.hour, parsedValue.minute) : "";
17154
+ const draftDisplay = this.draftHour !== null ? this.formatDisplay(this.draftHour, this.draftMinute ?? 0) : "";
17155
+ const hourOptions = this.getHourOptions();
17156
+ const minuteOptions = this.getMinuteOptions();
17157
+ const draftPeriod = this.draftPeriod;
17158
+ const wrapperClasses = [
17159
+ "time-picker-wrapper",
17160
+ this.size,
17161
+ isError ? "error" : "",
17162
+ this.readonly ? "readonly" : ""
17163
+ ].filter(Boolean).join(" ");
16701
17164
  return import_lit54.html`
16702
- <div part="base" class="toast ${this.type} ${this.visible ? "" : "hidden"}" role="status" aria-live="polite">
16703
- <span part="label" class="toast-message">${this.message}</span>
17165
+ <div part="base" class="${wrapperClasses}">
17166
+ ${this.label ? import_lit54.html`<label part="label" class="label" id="time-picker-label"
17167
+ >${this.label}${this.required ? import_lit54.html`<span class="required-mark" aria-hidden="true">*</span>` : import_lit54.nothing}</label
17168
+ >` : import_lit54.nothing}
16704
17169
 
16705
- ${this.actionLabel ? import_lit54.html`<button
16706
- part="action" class="toast-action"
16707
- @click="${this.handleActionClick}"
16708
- >
16709
- ${this.actionLabel}
16710
- </button>` : ""}
17170
+ ${this.name ? import_lit54.html`<input type="hidden" name=${this.name} .value=${this.value ?? ""} />` : import_lit54.nothing}
16711
17171
 
16712
- <button part="close-button" class="toast-close" @click="${this.close}" aria-label="Dismiss">✕</button>
16713
- </div>
16714
- `;
16715
- }
16716
- };
16717
- RelToast.styles = import_lit54.css`
16718
- :host {
16719
- color: var(--rel-text-default);
16720
- position: fixed;
16721
- bottom: 24px;
16722
- left: 50%;
17172
+ <button
17173
+ part="trigger"
17174
+ class="trigger-button ${isError ? "error" : ""}"
17175
+ type="button"
17176
+ ?disabled=${this.disabled}
17177
+ @click=${this.toggleTimePopover}
17178
+ @keydown=${this.handleTriggerKeydown}
17179
+ @focus=${() => this.dispatchEvent(
17180
+ new CustomEvent("rel-focus", { bubbles: true, composed: true })
17181
+ )}
17182
+ @blur=${() => this.dispatchEvent(
17183
+ new CustomEvent("rel-blur", { bubbles: true, composed: true })
17184
+ )}
17185
+ aria-label=${this.label || "Select time"}
17186
+ aria-haspopup="dialog"
17187
+ aria-expanded=${this.open}
17188
+ aria-required=${this.required}
17189
+ aria-invalid=${isError}
17190
+ aria-readonly=${this.readonly}
17191
+ aria-describedby=${describedById ?? import_lit54.nothing}
17192
+ aria-labelledby=${this.label ? "time-picker-label" : import_lit54.nothing}
17193
+ >
17194
+ <span part="value" class="trigger-content ${displayText ? "" : "placeholder"}">
17195
+ ${displayText || this.placeholder}
17196
+ </span>
17197
+ <span class="trigger-icons">
17198
+ ${this.clearable && this.value ? import_lit54.html`
17199
+ <button
17200
+ class="icon-button"
17201
+ type="button"
17202
+ aria-label="Clear time"
17203
+ @click=${this.clearValue}
17204
+ >
17205
+ <svg viewBox="0 0 16 16" fill="currentColor">
17206
+ <path
17207
+ d="M4 4l8 8M12 4l-8 8"
17208
+ stroke="currentColor"
17209
+ stroke-width="2"
17210
+ stroke-linecap="round"
17211
+ />
17212
+ </svg>
17213
+ </button>
17214
+ ` : import_lit54.nothing}
17215
+ <rel-icon part="icon" name="time-filled" size="sm"></rel-icon>
17216
+ </span>
17217
+ </button>
17218
+
17219
+ <div
17220
+ part="panel"
17221
+ class="popover ${this.open ? "open" : ""}"
17222
+ role="dialog"
17223
+ aria-label="Choose time"
17224
+ >
17225
+ <div class="time-readout">
17226
+ <span class="time-readout-label">Time</span>
17227
+ <span class="time-readout-value ${draftDisplay ? "" : "empty"}">
17228
+ ${draftDisplay || (this.format === "24h" ? "--:--" : "--:-- --")}
17229
+ </span>
17230
+ </div>
17231
+
17232
+ <div class="columns">
17233
+ <div class="column">
17234
+ <div class="column-header" aria-hidden="true">Hour</div>
17235
+ <div class="column-list" role="listbox" aria-label="Hours">
17236
+ ${hourOptions.map(
17237
+ (opt, i) => import_lit54.html`
17238
+ <button
17239
+ part="option"
17240
+ class="option-button ${this.draftHour === opt.hour24 ? "selected" : ""}"
17241
+ type="button"
17242
+ role="option"
17243
+ aria-selected=${this.draftHour === opt.hour24}
17244
+ ?disabled=${!this.isHourEnabled(opt.hour24)}
17245
+ @click=${() => this.selectHour(opt.hour24)}
17246
+ @keydown=${(e) => this.handleOptionKeydown(e, "hour")}
17247
+ tabindex=${this.draftHour === opt.hour24 || this.draftHour === null && i === 0 ? 0 : -1}
17248
+ >
17249
+ ${opt.label}
17250
+ </button>
17251
+ `
17252
+ )}
17253
+ </div>
17254
+ </div>
17255
+
17256
+ <div class="column">
17257
+ <div class="column-header" aria-hidden="true">Min</div>
17258
+ <div class="column-list" role="listbox" aria-label="Minutes">
17259
+ ${minuteOptions.map(
17260
+ (m, i) => import_lit54.html`
17261
+ <button
17262
+ part="option"
17263
+ class="option-button ${this.draftMinute === m ? "selected" : ""}"
17264
+ type="button"
17265
+ role="option"
17266
+ aria-selected=${this.draftMinute === m}
17267
+ ?disabled=${this.draftHour !== null && !this.isTimeInRange(this.draftHour, m)}
17268
+ @click=${() => this.selectMinute(m)}
17269
+ @keydown=${(e) => this.handleOptionKeydown(e, "minute")}
17270
+ tabindex=${this.draftMinute === m || this.draftMinute === null && i === 0 ? 0 : -1}
17271
+ >
17272
+ ${String(m).padStart(2, "0")}
17273
+ </button>
17274
+ `
17275
+ )}
17276
+ </div>
17277
+ </div>
17278
+
17279
+ ${this.format === "12h" ? import_lit54.html`
17280
+ <div class="column">
17281
+ <div class="column-header" aria-hidden="true">AM/PM</div>
17282
+ <div class="column-list" role="listbox" aria-label="AM or PM">
17283
+ ${["AM", "PM"].map(
17284
+ (p) => import_lit54.html`
17285
+ <button
17286
+ part="option"
17287
+ class="option-button ${draftPeriod === p ? "selected" : ""}"
17288
+ type="button"
17289
+ role="option"
17290
+ aria-selected=${draftPeriod === p}
17291
+ ?disabled=${!this.isPeriodEnabled(p)}
17292
+ @click=${() => this.selectPeriod(p)}
17293
+ @keydown=${(e) => this.handleOptionKeydown(e, "period")}
17294
+ tabindex=${draftPeriod === p || draftPeriod === null && p === "AM" ? 0 : -1}
17295
+ >
17296
+ ${p}
17297
+ </button>
17298
+ `
17299
+ )}
17300
+ </div>
17301
+ </div>
17302
+ ` : import_lit54.nothing}
17303
+ </div>
17304
+
17305
+ <div part="footer" class="time-footer">
17306
+ <rel-button
17307
+ variant="secondary"
17308
+ size="small"
17309
+ border="corner-radius"
17310
+ @click=${() => this.selectNow()}
17311
+ >
17312
+ Now
17313
+ </rel-button>
17314
+ <div class="footer-right">
17315
+ <rel-button
17316
+ variant="secondary"
17317
+ size="small"
17318
+ border="corner-radius"
17319
+ @click=${() => this.cancelPopover()}
17320
+ >
17321
+ Cancel
17322
+ </rel-button>
17323
+ <rel-button
17324
+ variant="primary"
17325
+ tone="default"
17326
+ size="small"
17327
+ border="corner-radius"
17328
+ ?disabled=${this.draftHour === null}
17329
+ @click=${() => this.applySelection()}
17330
+ >
17331
+ Apply
17332
+ </rel-button>
17333
+ </div>
17334
+ </div>
17335
+ </div>
17336
+
17337
+ ${belowText ? import_lit54.html`<div
17338
+ part="helper"
17339
+ class="time-picker-support ${isError ? "error" : ""}"
17340
+ id=${describedById}
17341
+ >
17342
+ ${belowText}
17343
+ </div>` : import_lit54.nothing}
17344
+ </div>
17345
+ `;
17346
+ }
17347
+ };
17348
+ RelTimePicker.styles = import_lit54.css`
17349
+ :host {
17350
+ color: var(--rel-text-default);
17351
+ display: block;
17352
+ font-family: var(--rel-fonts-font-family);
17353
+ position: relative;
17354
+ }
17355
+
17356
+ /* Intrinsic width by default; set fullWidth to fill the parent. */
17357
+ :host(:not([fullwidth])) {
17358
+ display: inline-block;
17359
+ width: auto;
17360
+ }
17361
+
17362
+ :host([disabled]) {
17363
+ opacity: 0.6;
17364
+ cursor: not-allowed;
17365
+ }
17366
+
17367
+ :host([disabled]) * {
17368
+ pointer-events: none;
17369
+ }
17370
+
17371
+ :host([readonly]) .trigger-button {
17372
+ cursor: default;
17373
+ }
17374
+
17375
+ .time-picker-wrapper {
17376
+ display: flex;
17377
+ flex-direction: column;
17378
+ gap: var(--rel-spacing-xs);
17379
+ }
17380
+
17381
+ .label {
17382
+ color: var(--rel-text-label);
17383
+ font-family: var(--rel-body-sm-medium-font-family);
17384
+ font-weight: var(--rel-body-sm-medium-font-weight);
17385
+ font-size: var(--rel-body-sm-medium-font-size);
17386
+ line-height: var(--rel-body-sm-medium-line-height);
17387
+ letter-spacing: var(--rel-body-sm-medium-letter-spacing);
17388
+ }
17389
+
17390
+ .required-mark {
17391
+ color: var(--rel-text-danger);
17392
+ margin-left: 2px;
17393
+ }
17394
+
17395
+ /* Support text (helperText / errorMessage) */
17396
+ .time-picker-support {
17397
+ color: var(--rel-text-placeholder);
17398
+ font-family: var(--rel-body-xs-regular-font-family);
17399
+ font-weight: var(--rel-body-xs-regular-font-weight);
17400
+ font-size: var(--rel-body-xs-regular-font-size);
17401
+ line-height: var(--rel-body-xs-regular-line-height);
17402
+ letter-spacing: var(--rel-body-xs-regular-letter-spacing);
17403
+ }
17404
+
17405
+ .time-picker-support.error {
17406
+ color: var(--rel-text-danger);
17407
+ }
17408
+
17409
+ .trigger-button {
17410
+ width: 100%;
17411
+ min-width: 160px;
17412
+ display: flex;
17413
+ align-items: center;
17414
+ justify-content: space-between;
17415
+ gap: var(--rel-spacing-xs);
17416
+ padding: var(--rel-spacing-sm) var(--rel-spacing-md);
17417
+ background: var(--rel-bg-surface);
17418
+ border: 1px solid var(--rel-border-default);
17419
+ border-radius: var(--rel-border-radius-sm);
17420
+ color: var(--rel-text-default);
17421
+ cursor: pointer;
17422
+ transition: all 0.15s ease;
17423
+ text-align: left;
17424
+ font-family: var(--rel-body-md-regular-font-family);
17425
+ font-weight: var(--rel-body-md-regular-font-weight);
17426
+ font-size: var(--rel-body-md-regular-font-size);
17427
+ line-height: var(--rel-body-md-regular-line-height);
17428
+ letter-spacing: var(--rel-body-md-regular-letter-spacing);
17429
+ }
17430
+
17431
+ .trigger-button:hover:not(:disabled) {
17432
+ border-color: var(--rel-border-strong);
17433
+ }
17434
+
17435
+ .trigger-button:focus-visible {
17436
+ outline: 2px solid var(--rel-border-focus);
17437
+ outline-offset: 2px;
17438
+ border-color: var(--rel-border-focus);
17439
+ }
17440
+
17441
+ .trigger-button:disabled {
17442
+ cursor: not-allowed;
17443
+ background: var(--rel-bg-surface-elevated);
17444
+ }
17445
+
17446
+ /* Error state */
17447
+ .trigger-button.error,
17448
+ .trigger-button.error:hover:not(:disabled) {
17449
+ border-color: var(--rel-border-danger);
17450
+ }
17451
+
17452
+ .trigger-button.error:focus-visible {
17453
+ outline-color: var(--rel-border-danger);
17454
+ border-color: var(--rel-border-danger);
17455
+ }
17456
+
17457
+ /* Size variants (medium is the base .trigger-button style) */
17458
+ .time-picker-wrapper.small .trigger-button {
17459
+ padding: var(--rel-spacing-xs) var(--rel-spacing-sm);
17460
+ font-family: var(--rel-body-sm-regular-font-family);
17461
+ font-weight: var(--rel-body-sm-regular-font-weight);
17462
+ font-size: var(--rel-body-sm-regular-font-size);
17463
+ line-height: var(--rel-body-sm-regular-line-height);
17464
+ letter-spacing: var(--rel-body-sm-regular-letter-spacing);
17465
+ }
17466
+
17467
+ .time-picker-wrapper.large .trigger-button {
17468
+ padding: var(--rel-spacing-md) var(--rel-spacing-md);
17469
+ font-family: var(--rel-body-lg-regular-font-family);
17470
+ font-weight: var(--rel-body-lg-regular-font-weight);
17471
+ font-size: var(--rel-body-lg-regular-font-size);
17472
+ line-height: var(--rel-body-lg-regular-line-height);
17473
+ letter-spacing: var(--rel-body-lg-regular-letter-spacing);
17474
+ }
17475
+
17476
+ .trigger-content {
17477
+ flex: 1;
17478
+ color: var(--rel-text-default);
17479
+ }
17480
+
17481
+ .trigger-content.placeholder {
17482
+ color: var(--rel-text-placeholder);
17483
+ }
17484
+
17485
+ .trigger-icons {
17486
+ display: flex;
17487
+ align-items: center;
17488
+ gap: var(--rel-spacing-2xs);
17489
+ color: var(--rel-text-placeholder);
17490
+ }
17491
+
17492
+ .icon-button {
17493
+ background: none;
17494
+ border: none;
17495
+ padding: var(--rel-spacing-3xs);
17496
+ cursor: pointer;
17497
+ color: var(--rel-text-placeholder);
17498
+ display: flex;
17499
+ align-items: center;
17500
+ justify-content: center;
17501
+ border-radius: var(--rel-border-radius-xs);
17502
+ transition: all 0.15s ease;
17503
+ }
17504
+
17505
+ .icon-button:hover {
17506
+ background: var(--rel-bg-surface-elevated);
17507
+ color: var(--rel-text-default);
17508
+ }
17509
+
17510
+ .icon-button svg {
17511
+ width: 16px;
17512
+ height: 16px;
17513
+ }
17514
+
17515
+ .popover {
17516
+ position: absolute;
17517
+ top: calc(100% + 4px);
17518
+ left: 0;
17519
+ z-index: 1000;
17520
+ background: var(--rel-bg-surface);
17521
+ border: 1px solid var(--rel-border-default);
17522
+ border-radius: var(--rel-border-radius-sm);
17523
+ box-shadow: var(--rel-shadows-shadow-300);
17524
+ padding: var(--rel-spacing-md);
17525
+ display: none;
17526
+ }
17527
+
17528
+ .popover.open {
17529
+ display: block;
17530
+ }
17531
+
17532
+ /* Draft readout (mirrors the range-picker FROM/TO block) */
17533
+ .time-readout {
17534
+ display: flex;
17535
+ align-items: baseline;
17536
+ gap: var(--rel-spacing-sm);
17537
+ padding-bottom: var(--rel-spacing-sm);
17538
+ margin-bottom: var(--rel-spacing-sm);
17539
+ border-bottom: 1px solid var(--rel-border-subtle);
17540
+ }
17541
+
17542
+ .time-readout-label {
17543
+ color: var(--rel-text-placeholder);
17544
+ text-transform: uppercase;
17545
+ font-family: var(--rel-body-xs-semibold-font-family);
17546
+ font-weight: var(--rel-body-xs-semibold-font-weight);
17547
+ font-size: var(--rel-body-xs-semibold-font-size);
17548
+ line-height: var(--rel-body-xs-semibold-line-height);
17549
+ letter-spacing: var(--rel-body-xs-semibold-letter-spacing);
17550
+ }
17551
+
17552
+ .time-readout-value {
17553
+ color: var(--rel-text-default);
17554
+ font-family: var(--rel-body-md-semibold-font-family);
17555
+ font-weight: var(--rel-body-md-semibold-font-weight);
17556
+ font-size: var(--rel-body-md-semibold-font-size);
17557
+ line-height: var(--rel-body-md-semibold-line-height);
17558
+ letter-spacing: var(--rel-body-md-semibold-letter-spacing);
17559
+ }
17560
+
17561
+ .time-readout-value.empty {
17562
+ color: var(--rel-text-placeholder);
17563
+ }
17564
+
17565
+ .columns {
17566
+ display: flex;
17567
+ gap: var(--rel-spacing-xs);
17568
+ }
17569
+
17570
+ /* Columns share the panel width equally, so the two-column 24h layout
17571
+ fills the same footprint the footer dictates instead of bunching left. */
17572
+ .column {
17573
+ display: flex;
17574
+ flex-direction: column;
17575
+ flex: 1;
17576
+ min-width: 64px;
17577
+ }
17578
+
17579
+ .column-header {
17580
+ text-align: center;
17581
+ color: var(--rel-text-placeholder);
17582
+ padding: var(--rel-spacing-xs);
17583
+ text-transform: uppercase;
17584
+ font-family: var(--rel-body-xs-semibold-font-family);
17585
+ font-weight: var(--rel-body-xs-semibold-font-weight);
17586
+ font-size: var(--rel-body-xs-semibold-font-size);
17587
+ line-height: var(--rel-body-xs-semibold-line-height);
17588
+ letter-spacing: var(--rel-body-xs-semibold-letter-spacing);
17589
+ }
17590
+
17591
+ .column-list {
17592
+ display: flex;
17593
+ flex-direction: column;
17594
+ gap: var(--rel-spacing-3xs);
17595
+ max-height: 224px;
17596
+ overflow-y: auto;
17597
+ padding: var(--rel-spacing-3xs);
17598
+ scrollbar-width: thin;
17599
+ }
17600
+
17601
+ .option-button {
17602
+ border: none;
17603
+ background: transparent;
17604
+ border-radius: var(--rel-border-radius-sm);
17605
+ color: var(--rel-text-default);
17606
+ cursor: pointer;
17607
+ padding: var(--rel-spacing-xs) var(--rel-spacing-sm);
17608
+ text-align: center;
17609
+ flex-shrink: 0;
17610
+ transition: all 0.15s ease;
17611
+ font-family: var(--rel-body-sm-medium-font-family);
17612
+ font-weight: var(--rel-body-sm-medium-font-weight);
17613
+ font-size: var(--rel-body-sm-medium-font-size);
17614
+ line-height: var(--rel-body-sm-medium-line-height);
17615
+ letter-spacing: var(--rel-body-sm-medium-letter-spacing);
17616
+ }
17617
+
17618
+ .option-button:hover:not(:disabled):not(.selected) {
17619
+ background: var(--rel-bg-surface-elevated);
17620
+ }
17621
+
17622
+ .option-button:focus-visible {
17623
+ outline: 2px solid var(--rel-border-focus);
17624
+ outline-offset: -2px;
17625
+ z-index: 1;
17626
+ }
17627
+
17628
+ .option-button.selected {
17629
+ background: var(--rel-action-brand-fill);
17630
+ color: var(--rel-action-brand-label-icons-primary);
17631
+ font-weight: var(--rel-body-md-semibold-font-weight);
17632
+ }
17633
+
17634
+ .option-button:disabled {
17635
+ color: var(--rel-text-disabled);
17636
+ cursor: not-allowed;
17637
+ opacity: 0.5;
17638
+ }
17639
+
17640
+ .option-button:disabled:hover {
17641
+ background: transparent;
17642
+ }
17643
+
17644
+ /* Footer (mirrors the range-picker calendar-footer) */
17645
+ .time-footer {
17646
+ display: flex;
17647
+ align-items: center;
17648
+ justify-content: space-between;
17649
+ gap: var(--rel-spacing-sm);
17650
+ padding-top: var(--rel-spacing-sm);
17651
+ margin-top: var(--rel-spacing-sm);
17652
+ border-top: 1px solid var(--rel-border-subtle);
17653
+ }
17654
+
17655
+ .footer-right {
17656
+ display: flex;
17657
+ align-items: center;
17658
+ gap: var(--rel-spacing-xs);
17659
+ }
17660
+
17661
+ @media (prefers-reduced-motion: reduce) {
17662
+ .trigger-button,
17663
+ .icon-button,
17664
+ .option-button {
17665
+ transition: none;
17666
+ }
17667
+ }
17668
+ `;
17669
+ __decorateClass([
17670
+ (0, import_decorators54.property)({ type: String, reflect: true })
17671
+ ], RelTimePicker.prototype, "value", 2);
17672
+ __decorateClass([
17673
+ (0, import_decorators54.property)({ type: String })
17674
+ ], RelTimePicker.prototype, "placeholder", 2);
17675
+ __decorateClass([
17676
+ (0, import_decorators54.property)({ type: String })
17677
+ ], RelTimePicker.prototype, "label", 2);
17678
+ __decorateClass([
17679
+ (0, import_decorators54.property)({ type: Boolean, reflect: true })
17680
+ ], RelTimePicker.prototype, "disabled", 2);
17681
+ __decorateClass([
17682
+ (0, import_decorators54.property)({ type: Boolean })
17683
+ ], RelTimePicker.prototype, "required", 2);
17684
+ __decorateClass([
17685
+ (0, import_decorators54.property)({ type: Boolean, reflect: true })
17686
+ ], RelTimePicker.prototype, "readonly", 2);
17687
+ __decorateClass([
17688
+ (0, import_decorators54.property)({ type: String })
17689
+ ], RelTimePicker.prototype, "format", 2);
17690
+ __decorateClass([
17691
+ (0, import_decorators54.property)({ type: Number, attribute: "minute-step" })
17692
+ ], RelTimePicker.prototype, "minuteStep", 2);
17693
+ __decorateClass([
17694
+ (0, import_decorators54.property)({ type: String, attribute: "min-time" })
17695
+ ], RelTimePicker.prototype, "minTime", 2);
17696
+ __decorateClass([
17697
+ (0, import_decorators54.property)({ type: String, attribute: "max-time" })
17698
+ ], RelTimePicker.prototype, "maxTime", 2);
17699
+ __decorateClass([
17700
+ (0, import_decorators54.property)({ type: Boolean, reflect: true })
17701
+ ], RelTimePicker.prototype, "open", 2);
17702
+ __decorateClass([
17703
+ (0, import_decorators54.property)({ type: Boolean })
17704
+ ], RelTimePicker.prototype, "clearable", 2);
17705
+ __decorateClass([
17706
+ (0, import_decorators54.property)({ type: Boolean })
17707
+ ], RelTimePicker.prototype, "error", 2);
17708
+ __decorateClass([
17709
+ (0, import_decorators54.property)({ type: Boolean })
17710
+ ], RelTimePicker.prototype, "invalid", 2);
17711
+ __decorateClass([
17712
+ (0, import_decorators54.property)({ type: String, attribute: "error-message" })
17713
+ ], RelTimePicker.prototype, "errorMessage", 2);
17714
+ __decorateClass([
17715
+ (0, import_decorators54.property)({ type: String, attribute: "helper-text" })
17716
+ ], RelTimePicker.prototype, "helperText", 2);
17717
+ __decorateClass([
17718
+ (0, import_decorators54.property)({ type: String })
17719
+ ], RelTimePicker.prototype, "name", 2);
17720
+ __decorateClass([
17721
+ (0, import_decorators54.property)({ type: String })
17722
+ ], RelTimePicker.prototype, "size", 2);
17723
+ __decorateClass([
17724
+ (0, import_decorators54.property)({ type: String, reflect: true })
17725
+ ], RelTimePicker.prototype, "variant", 2);
17726
+ __decorateClass([
17727
+ (0, import_decorators54.property)({ type: Boolean, reflect: true })
17728
+ ], RelTimePicker.prototype, "fullWidth", 2);
17729
+ __decorateClass([
17730
+ (0, import_decorators54.state)()
17731
+ ], RelTimePicker.prototype, "draftHour", 2);
17732
+ __decorateClass([
17733
+ (0, import_decorators54.state)()
17734
+ ], RelTimePicker.prototype, "draftMinute", 2);
17735
+ __decorateClass([
17736
+ (0, import_decorators54.query)(".trigger-button")
17737
+ ], RelTimePicker.prototype, "triggerButton", 2);
17738
+ __decorateClass([
17739
+ (0, import_decorators54.query)(".columns")
17740
+ ], RelTimePicker.prototype, "columnsElement", 2);
17741
+ RelTimePicker = __decorateClass([
17742
+ (0, import_decorators54.customElement)("rel-time-picker")
17743
+ ], RelTimePicker);
17744
+
17745
+ // src/components/rel-toast/rel-toast.ts
17746
+ var import_lit55 = require("lit");
17747
+ var import_decorators55 = require("lit/decorators.js");
17748
+ var RelToast = class extends import_lit55.LitElement {
17749
+ constructor() {
17750
+ super(...arguments);
17751
+ this.message = "";
17752
+ this.type = "default";
17753
+ this.duration = 4e3;
17754
+ this.show = false;
17755
+ this.visible = false;
17756
+ this._dismissTimer = null;
17757
+ }
17758
+ willUpdate(changed) {
17759
+ if (!changed.has("show")) return;
17760
+ if (this.show) {
17761
+ this.visible = true;
17762
+ if (this._dismissTimer) clearTimeout(this._dismissTimer);
17763
+ if (this.duration > 0) {
17764
+ this._dismissTimer = setTimeout(() => this.close(), this.duration);
17765
+ }
17766
+ } else {
17767
+ this.visible = false;
17768
+ if (this._dismissTimer) {
17769
+ clearTimeout(this._dismissTimer);
17770
+ this._dismissTimer = null;
17771
+ }
17772
+ }
17773
+ }
17774
+ disconnectedCallback() {
17775
+ super.disconnectedCallback();
17776
+ if (this._dismissTimer) clearTimeout(this._dismissTimer);
17777
+ }
17778
+ open() {
17779
+ this.show = true;
17780
+ }
17781
+ close() {
17782
+ this.show = false;
17783
+ this.visible = false;
17784
+ if (this._dismissTimer) {
17785
+ clearTimeout(this._dismissTimer);
17786
+ this._dismissTimer = null;
17787
+ }
17788
+ this.dispatchEvent(
17789
+ new CustomEvent("dismissed", {
17790
+ bubbles: true,
17791
+ composed: true
17792
+ })
17793
+ );
17794
+ }
17795
+ handleActionClick(event) {
17796
+ event.stopPropagation();
17797
+ this.dispatchEvent(
17798
+ new CustomEvent("action", {
17799
+ bubbles: true,
17800
+ composed: true
17801
+ })
17802
+ );
17803
+ this.close();
17804
+ }
17805
+ render() {
17806
+ return import_lit55.html`
17807
+ <div part="base" class="toast ${this.type} ${this.visible ? "" : "hidden"}" role="status" aria-live="polite">
17808
+ <span part="label" class="toast-message">${this.message}</span>
17809
+
17810
+ ${this.actionLabel ? import_lit55.html`<button
17811
+ part="action" class="toast-action"
17812
+ @click="${this.handleActionClick}"
17813
+ >
17814
+ ${this.actionLabel}
17815
+ </button>` : ""}
17816
+
17817
+ <button part="close-button" class="toast-close" @click="${this.close}" aria-label="Dismiss">✕</button>
17818
+ </div>
17819
+ `;
17820
+ }
17821
+ };
17822
+ RelToast.styles = import_lit55.css`
17823
+ :host {
17824
+ color: var(--rel-text-default);
17825
+ position: fixed;
17826
+ bottom: 24px;
17827
+ left: 50%;
16723
17828
  transform: translateX(-50%);
16724
17829
  display: flex;
16725
17830
  justify-content: center;
@@ -16832,31 +17937,31 @@ RelToast.styles = import_lit54.css`
16832
17937
  }
16833
17938
  `;
16834
17939
  __decorateClass([
16835
- (0, import_decorators54.property)({ type: String })
17940
+ (0, import_decorators55.property)({ type: String })
16836
17941
  ], RelToast.prototype, "message", 2);
16837
17942
  __decorateClass([
16838
- (0, import_decorators54.property)({ type: String })
17943
+ (0, import_decorators55.property)({ type: String })
16839
17944
  ], RelToast.prototype, "type", 2);
16840
17945
  __decorateClass([
16841
- (0, import_decorators54.property)({ type: String })
17946
+ (0, import_decorators55.property)({ type: String })
16842
17947
  ], RelToast.prototype, "actionLabel", 2);
16843
17948
  __decorateClass([
16844
- (0, import_decorators54.property)({ type: Number })
17949
+ (0, import_decorators55.property)({ type: Number })
16845
17950
  ], RelToast.prototype, "duration", 2);
16846
17951
  __decorateClass([
16847
- (0, import_decorators54.property)({ type: Boolean, reflect: true })
17952
+ (0, import_decorators55.property)({ type: Boolean, reflect: true })
16848
17953
  ], RelToast.prototype, "show", 2);
16849
17954
  __decorateClass([
16850
- (0, import_decorators54.state)()
17955
+ (0, import_decorators55.state)()
16851
17956
  ], RelToast.prototype, "visible", 2);
16852
17957
  RelToast = __decorateClass([
16853
- (0, import_decorators54.customElement)("rel-toast")
17958
+ (0, import_decorators55.customElement)("rel-toast")
16854
17959
  ], RelToast);
16855
17960
 
16856
17961
  // src/components/rel-tooltip/rel-tooltip.ts
16857
- var import_lit55 = require("lit");
16858
- var import_decorators55 = require("lit/decorators.js");
16859
- var RelTooltip = class extends import_lit55.LitElement {
17962
+ var import_lit56 = require("lit");
17963
+ var import_decorators56 = require("lit/decorators.js");
17964
+ var RelTooltip = class extends import_lit56.LitElement {
16860
17965
  constructor() {
16861
17966
  super(...arguments);
16862
17967
  this.text = "";
@@ -16878,7 +17983,7 @@ var RelTooltip = class extends import_lit55.LitElement {
16878
17983
  }
16879
17984
  }
16880
17985
  render() {
16881
- return import_lit55.html`
17986
+ return import_lit56.html`
16882
17987
  <slot @slotchange="${this.linkTrigger}"></slot>
16883
17988
  <div
16884
17989
  part="panel" class="tooltip-bubble ${this.position}"
@@ -16886,12 +17991,12 @@ var RelTooltip = class extends import_lit55.LitElement {
16886
17991
  role="tooltip"
16887
17992
  >
16888
17993
  ${this.text}
16889
- ${this.showTail ? import_lit55.html`<span part="indicator" class="tooltip-tail"></span>` : ""}
17994
+ ${this.showTail ? import_lit56.html`<span part="indicator" class="tooltip-tail"></span>` : ""}
16890
17995
  </div>
16891
17996
  `;
16892
17997
  }
16893
17998
  };
16894
- RelTooltip.styles = import_lit55.css`
17999
+ RelTooltip.styles = import_lit56.css`
16895
18000
  :host {
16896
18001
  color: var(--rel-text-default);
16897
18002
  display: inline-block;
@@ -17005,19 +18110,19 @@ RelTooltip.styles = import_lit55.css`
17005
18110
  }
17006
18111
  `;
17007
18112
  __decorateClass([
17008
- (0, import_decorators55.property)({ type: String })
18113
+ (0, import_decorators56.property)({ type: String })
17009
18114
  ], RelTooltip.prototype, "text", 2);
17010
18115
  __decorateClass([
17011
- (0, import_decorators55.property)({ type: String })
18116
+ (0, import_decorators56.property)({ type: String })
17012
18117
  ], RelTooltip.prototype, "position", 2);
17013
18118
  __decorateClass([
17014
- (0, import_decorators55.property)({ type: Boolean, attribute: "show-tail" })
18119
+ (0, import_decorators56.property)({ type: Boolean, attribute: "show-tail" })
17015
18120
  ], RelTooltip.prototype, "showTail", 2);
17016
18121
  __decorateClass([
17017
- (0, import_decorators55.property)({ type: String, reflect: true })
18122
+ (0, import_decorators56.property)({ type: String, reflect: true })
17018
18123
  ], RelTooltip.prototype, "type", 2);
17019
18124
  RelTooltip = __decorateClass([
17020
- (0, import_decorators55.customElement)("rel-tooltip")
18125
+ (0, import_decorators56.customElement)("rel-tooltip")
17021
18126
  ], RelTooltip);
17022
18127
 
17023
18128
  // src/index.ts
@@ -17071,6 +18176,7 @@ __reExport(index_exports, require("@reliability-design/icons"), module.exports);
17071
18176
  RelTab,
17072
18177
  RelTabItem,
17073
18178
  RelTextfield,
18179
+ RelTimePicker,
17074
18180
  RelToast,
17075
18181
  RelTooltip,
17076
18182
  RelTopbar,