@xmesh/system-design 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/README.md +472 -0
  2. package/assets/brand-lockup-dark.svg +9 -0
  3. package/assets/brand-lockup-light.svg +9 -0
  4. package/assets/brand-mark.svg +9 -0
  5. package/colors_and_type.css +11 -0
  6. package/dist/lit/components/alert/index.css +201 -0
  7. package/dist/lit/components/alert/index.d.ts +25 -0
  8. package/dist/lit/components/alert/index.js +191 -0
  9. package/dist/lit/components/app-bar/index.css +80 -0
  10. package/dist/lit/components/app-bar/index.d.ts +19 -0
  11. package/dist/lit/components/app-bar/index.js +120 -0
  12. package/dist/lit/components/artifact/index.css +166 -0
  13. package/dist/lit/components/artifact/index.d.ts +37 -0
  14. package/dist/lit/components/artifact/index.js +294 -0
  15. package/dist/lit/components/autocomplete/index.css +171 -0
  16. package/dist/lit/components/autocomplete/index.d.ts +47 -0
  17. package/dist/lit/components/autocomplete/index.js +404 -0
  18. package/dist/lit/components/avatar/index.css +62 -0
  19. package/dist/lit/components/avatar/index.d.ts +19 -0
  20. package/dist/lit/components/avatar/index.js +112 -0
  21. package/dist/lit/components/avatar-group/index.css +60 -0
  22. package/dist/lit/components/avatar-group/index.d.ts +19 -0
  23. package/dist/lit/components/avatar-group/index.js +97 -0
  24. package/dist/lit/components/badge/index.css +72 -0
  25. package/dist/lit/components/badge/index.d.ts +18 -0
  26. package/dist/lit/components/badge/index.js +115 -0
  27. package/dist/lit/components/brand-mark/index.css +109 -0
  28. package/dist/lit/components/brand-mark/index.d.ts +24 -0
  29. package/dist/lit/components/brand-mark/index.js +116 -0
  30. package/dist/lit/components/breadcrumbs/index.css +91 -0
  31. package/dist/lit/components/breadcrumbs/index.d.ts +19 -0
  32. package/dist/lit/components/breadcrumbs/index.js +104 -0
  33. package/dist/lit/components/bubble/index.css +182 -0
  34. package/dist/lit/components/bubble/index.d.ts +72 -0
  35. package/dist/lit/components/bubble/index.js +617 -0
  36. package/dist/lit/components/button/index.css +342 -0
  37. package/dist/lit/components/button/index.d.ts +32 -0
  38. package/dist/lit/components/button/index.js +202 -0
  39. package/dist/lit/components/card/index.css +99 -0
  40. package/dist/lit/components/card/index.d.ts +20 -0
  41. package/dist/lit/components/card/index.js +133 -0
  42. package/dist/lit/components/chat/index.css +292 -0
  43. package/dist/lit/components/chat/index.d.ts +74 -0
  44. package/dist/lit/components/chat/index.js +589 -0
  45. package/dist/lit/components/checkbox/index.css +126 -0
  46. package/dist/lit/components/checkbox/index.d.ts +21 -0
  47. package/dist/lit/components/checkbox/index.js +138 -0
  48. package/dist/lit/components/chip/index.css +145 -0
  49. package/dist/lit/components/chip/index.d.ts +30 -0
  50. package/dist/lit/components/chip/index.js +230 -0
  51. package/dist/lit/components/chip-group/index.css +19 -0
  52. package/dist/lit/components/chip-group/index.d.ts +24 -0
  53. package/dist/lit/components/chip-group/index.js +171 -0
  54. package/dist/lit/components/code/index.css +42 -0
  55. package/dist/lit/components/code/index.d.ts +12 -0
  56. package/dist/lit/components/code/index.js +68 -0
  57. package/dist/lit/components/composer/index.css +548 -0
  58. package/dist/lit/components/composer/index.d.ts +67 -0
  59. package/dist/lit/components/composer/index.js +713 -0
  60. package/dist/lit/components/data-table/index.css +166 -0
  61. package/dist/lit/components/data-table/index.d.ts +55 -0
  62. package/dist/lit/components/data-table/index.js +390 -0
  63. package/dist/lit/components/dialog/index.css +124 -0
  64. package/dist/lit/components/dialog/index.d.ts +24 -0
  65. package/dist/lit/components/dialog/index.js +199 -0
  66. package/dist/lit/components/divider/index.css +27 -0
  67. package/dist/lit/components/divider/index.d.ts +13 -0
  68. package/dist/lit/components/divider/index.js +67 -0
  69. package/dist/lit/components/empty-state/index.css +69 -0
  70. package/dist/lit/components/empty-state/index.d.ts +21 -0
  71. package/dist/lit/components/empty-state/index.js +123 -0
  72. package/dist/lit/components/expansion-panel/index.css +120 -0
  73. package/dist/lit/components/expansion-panel/index.d.ts +22 -0
  74. package/dist/lit/components/expansion-panel/index.js +174 -0
  75. package/dist/lit/components/field/index.css +223 -0
  76. package/dist/lit/components/field/index.d.ts +106 -0
  77. package/dist/lit/components/field/index.js +388 -0
  78. package/dist/lit/components/file-input/index.css +257 -0
  79. package/dist/lit/components/file-input/index.d.ts +30 -0
  80. package/dist/lit/components/file-input/index.js +298 -0
  81. package/dist/lit/components/form/index.css +29 -0
  82. package/dist/lit/components/form/index.d.ts +38 -0
  83. package/dist/lit/components/form/index.js +192 -0
  84. package/dist/lit/components/grid/index.css +53 -0
  85. package/dist/lit/components/grid/index.d.ts +14 -0
  86. package/dist/lit/components/grid/index.js +82 -0
  87. package/dist/lit/components/kbd/index.css +35 -0
  88. package/dist/lit/components/kbd/index.d.ts +11 -0
  89. package/dist/lit/components/kbd/index.js +43 -0
  90. package/dist/lit/components/list/index.css +15 -0
  91. package/dist/lit/components/list/index.d.ts +28 -0
  92. package/dist/lit/components/list/index.js +188 -0
  93. package/dist/lit/components/list-item/index.css +119 -0
  94. package/dist/lit/components/list-item/index.d.ts +20 -0
  95. package/dist/lit/components/list-item/index.js +127 -0
  96. package/dist/lit/components/menu/index.css +94 -0
  97. package/dist/lit/components/menu/index.d.ts +47 -0
  98. package/dist/lit/components/menu/index.js +386 -0
  99. package/dist/lit/components/navigation-drawer/index.css +114 -0
  100. package/dist/lit/components/navigation-drawer/index.d.ts +29 -0
  101. package/dist/lit/components/navigation-drawer/index.js +218 -0
  102. package/dist/lit/components/overlay/index.css +171 -0
  103. package/dist/lit/components/overlay/index.d.ts +65 -0
  104. package/dist/lit/components/overlay/index.js +566 -0
  105. package/dist/lit/components/pagination/index.css +102 -0
  106. package/dist/lit/components/pagination/index.d.ts +22 -0
  107. package/dist/lit/components/pagination/index.js +184 -0
  108. package/dist/lit/components/primitives/index.css +504 -0
  109. package/dist/lit/components/primitives/index.d.ts +25 -0
  110. package/dist/lit/components/primitives/index.js +283 -0
  111. package/dist/lit/components/progress/index.css +143 -0
  112. package/dist/lit/components/progress/index.d.ts +23 -0
  113. package/dist/lit/components/progress/index.js +180 -0
  114. package/dist/lit/components/radio-group/index.css +178 -0
  115. package/dist/lit/components/radio-group/index.d.ts +35 -0
  116. package/dist/lit/components/radio-group/index.js +292 -0
  117. package/dist/lit/components/select/index.css +151 -0
  118. package/dist/lit/components/select/index.d.ts +50 -0
  119. package/dist/lit/components/select/index.js +390 -0
  120. package/dist/lit/components/sidebar-item/index.css +133 -0
  121. package/dist/lit/components/sidebar-item/index.d.ts +20 -0
  122. package/dist/lit/components/sidebar-item/index.js +105 -0
  123. package/dist/lit/components/skeleton/index.css +81 -0
  124. package/dist/lit/components/skeleton/index.d.ts +19 -0
  125. package/dist/lit/components/skeleton/index.js +119 -0
  126. package/dist/lit/components/slider/index.css +171 -0
  127. package/dist/lit/components/slider/index.d.ts +36 -0
  128. package/dist/lit/components/slider/index.js +302 -0
  129. package/dist/lit/components/snackbar/index.css +279 -0
  130. package/dist/lit/components/snackbar/index.d.ts +33 -0
  131. package/dist/lit/components/snackbar/index.js +195 -0
  132. package/dist/lit/components/stack/index.css +41 -0
  133. package/dist/lit/components/stack/index.d.ts +20 -0
  134. package/dist/lit/components/stack/index.js +103 -0
  135. package/dist/lit/components/switch/index.css +126 -0
  136. package/dist/lit/components/switch/index.d.ts +17 -0
  137. package/dist/lit/components/switch/index.js +116 -0
  138. package/dist/lit/components/table/index.css +85 -0
  139. package/dist/lit/components/table/index.d.ts +25 -0
  140. package/dist/lit/components/table/index.js +139 -0
  141. package/dist/lit/components/tabs/index.css +116 -0
  142. package/dist/lit/components/tabs/index.d.ts +49 -0
  143. package/dist/lit/components/tabs/index.js +320 -0
  144. package/dist/lit/components/text-field/index.css +90 -0
  145. package/dist/lit/components/text-field/index.d.ts +17 -0
  146. package/dist/lit/components/text-field/index.js +101 -0
  147. package/dist/lit/components/textarea/index.css +55 -0
  148. package/dist/lit/components/textarea/index.d.ts +26 -0
  149. package/dist/lit/components/textarea/index.js +124 -0
  150. package/dist/lit/components/tooltip/index.css +37 -0
  151. package/dist/lit/components/tooltip/index.d.ts +31 -0
  152. package/dist/lit/components/tooltip/index.js +196 -0
  153. package/dist/lit/components/validation/index.css +386 -0
  154. package/dist/lit/components/validation/index.d.ts +45 -0
  155. package/dist/lit/components/validation/index.js +318 -0
  156. package/dist/lit/index.d.ts +50 -0
  157. package/dist/lit/index.js +59 -0
  158. package/package.json +81 -0
  159. package/styles/README.md +346 -0
  160. package/styles/_elevation.css +24 -0
  161. package/styles/_fonts.css +6 -0
  162. package/styles/_layout.css +37 -0
  163. package/styles/_primitives.css +154 -0
  164. package/styles/_scroll.css +75 -0
  165. package/styles/_semantic.css +146 -0
  166. package/styles/_space.css +61 -0
  167. package/styles/_type.css +139 -0
  168. package/styles/_xmesh-extensions.css +232 -0
  169. package/styles/index.css +44 -0
  170. package/styles/md3/_color.css +102 -0
  171. package/styles/md3/_elevation.css +26 -0
  172. package/styles/md3/_motion.css +35 -0
  173. package/styles/md3/_shape.css +22 -0
  174. package/styles/md3/_state.css +22 -0
  175. package/styles/md3/_type.css +111 -0
@@ -0,0 +1,124 @@
1
+ /*
2
+ textarea/index.ts — <xm-textarea>, a multi-line XmField subclass (Story 2.2).
3
+
4
+ The only delta from <xm-text-field> is the control: a native <textarea>
5
+ projected into the base control wrapper via renderControl(), plus `rows`,
6
+ `auto-grow`, and `max-rows`. Everything else — label row, helper/error row,
7
+ required marker, focus ring, disabled/readonly/loading, ARIA wiring, form
8
+ association, and the uncontrolled-first value lifecycle — is inherited from
9
+ XmField (AD-7), never re-implemented.
10
+
11
+ Authoring:
12
+ <xm-textarea
13
+ label="Description"
14
+ rows="4"
15
+ placeholder="What does this agent do?"
16
+ helper="Shown on the agent's card."
17
+ ></xm-textarea>
18
+
19
+ <xm-textarea label="Notes" auto-grow max-rows="8"></xm-textarea>
20
+
21
+ Value ownership is uncontrolled-first (AD-6): the `value` attribute seeds the
22
+ initial value once; emitInput / emitChange fire bubbling + composed `input`
23
+ (per keystroke) and `change` (on commit) with detail.value (AD-8a).
24
+
25
+ Keyboard: native <textarea> semantics — Enter inserts a newline, Tab leaves
26
+ the field (no tab character inserted).
27
+
28
+ Shadow DOM. The native <textarea> is already styled by the base's
29
+ `.field__control textarea` rule; this component's CSS only owns the multi-row
30
+ geometry. Lit is a bare `import` (peer dep).
31
+ */
32
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
33
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
34
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
35
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
36
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
37
+ };
38
+ import { html, nothing } from "lit";
39
+ import { customElement, property, query } from "lit/decorators.js";
40
+ import { XmField } from "../field/index.js";
41
+ const TEXTAREA_CSS = new URL("../textarea/index.css", import.meta.url).href;
42
+ let XmTextarea = class XmTextarea extends XmField {
43
+ constructor() {
44
+ super(...arguments);
45
+ /** Initial visible height in text rows. */
46
+ this.rows = 3;
47
+ /** Native placeholder — shown when the live value is empty. */
48
+ this.placeholder = "";
49
+ /** Grow the textarea height with content up to `maxRows` (no scroll jitter). */
50
+ this.autoGrow = false;
51
+ /** Cap for auto-grow, in rows. Beyond it the textarea scrolls. */
52
+ this.maxRows = 8;
53
+ this._onInput = (e) => {
54
+ this.emitInput(e.target.value);
55
+ if (this.autoGrow)
56
+ this._resize();
57
+ };
58
+ this._onChange = (e) => {
59
+ this.emitChange(e.target.value);
60
+ };
61
+ }
62
+ updated(changed) {
63
+ super.updated?.(changed);
64
+ if (this.autoGrow)
65
+ this._resize();
66
+ }
67
+ /** Reset then snap to scrollHeight, clamped to maxRows. Reading scrollHeight
68
+ after a height reset is the only reliable shrink-and-grow measurement;
69
+ it's a single synchronous layout read per input, not an animation. */
70
+ _resize() {
71
+ const ta = this._textarea;
72
+ if (!ta)
73
+ return;
74
+ ta.style.height = "auto";
75
+ const cs = getComputedStyle(ta);
76
+ const lineHeight = parseFloat(cs.lineHeight) || 20;
77
+ const padV = parseFloat(cs.paddingTop) + parseFloat(cs.paddingBottom);
78
+ const max = lineHeight * this.maxRows + padV;
79
+ const next = Math.min(ta.scrollHeight, max);
80
+ ta.style.height = `${next}px`;
81
+ ta.style.overflowY = ta.scrollHeight > max ? "auto" : "hidden";
82
+ }
83
+ renderControl() {
84
+ const a = this.controlAria;
85
+ const controlCls = `textarea__control${this.autoGrow ? " textarea__control--auto-grow" : ""}`;
86
+ return html `
87
+ <link rel="stylesheet" href="${TEXTAREA_CSS}" />
88
+ <textarea
89
+ class="${controlCls}"
90
+ id=${a.id}
91
+ rows=${this.rows}
92
+ .value=${this._value}
93
+ placeholder=${this.placeholder || nothing}
94
+ name=${this.name || nothing}
95
+ aria-describedby=${a.describedBy ?? nothing}
96
+ aria-invalid=${a.invalid ?? "false"}
97
+ ?required=${this.required}
98
+ ?disabled=${this.effectiveDisabled}
99
+ ?readonly=${this.readonly}
100
+ @input=${this._onInput}
101
+ @change=${this._onChange}
102
+ ></textarea>
103
+ `;
104
+ }
105
+ };
106
+ __decorate([
107
+ property({ type: Number })
108
+ ], XmTextarea.prototype, "rows", void 0);
109
+ __decorate([
110
+ property({ type: String })
111
+ ], XmTextarea.prototype, "placeholder", void 0);
112
+ __decorate([
113
+ property({ type: Boolean, attribute: "auto-grow" })
114
+ ], XmTextarea.prototype, "autoGrow", void 0);
115
+ __decorate([
116
+ property({ type: Number, attribute: "max-rows" })
117
+ ], XmTextarea.prototype, "maxRows", void 0);
118
+ __decorate([
119
+ query(".textarea__control")
120
+ ], XmTextarea.prototype, "_textarea", void 0);
121
+ XmTextarea = __decorate([
122
+ customElement("xm-textarea")
123
+ ], XmTextarea);
124
+ export { XmTextarea };
@@ -0,0 +1,37 @@
1
+ /* ============================================
2
+ Tooltip — a small anchored contextual label.
3
+
4
+ The surface chrome (inverse-surface fill, inverse-on-surface ink, hairline
5
+ border, level3 elevation, small radius, edge-flip) is owned by the composed
6
+ <xm-overlay> in the `tooltip` tier — this file styles only the LABEL the
7
+ tooltip projects into the overlay, plus the trigger wrapper.
8
+
9
+ The label is a neutral, sentence-cased description — NO severity color, no
10
+ per-severity hue (AD-11). The ink is inverse-on-surface, inherited from the
11
+ overlay surface; it is restated here so the label reads correctly even if the
12
+ cascade is interrupted.
13
+
14
+ Motion (short3 fade/translate) is owned by the overlay's open transition.
15
+
16
+ BEM block: `tooltip`. Registered in scripts/check-bem.sh STRICT_BLOCKS.
17
+ Elements: __trigger (the anchored control wrapper), __label (the copy).
18
+ ============================================ */
19
+
20
+ .tooltip__trigger {
21
+ display: inline-flex;
22
+ align-items: center;
23
+ }
24
+
25
+ .tooltip__label {
26
+ display: block;
27
+ max-width: 240px;
28
+ /* Compact label scale; sentence case enforced by content, no transform. */
29
+ font-family: var(--md-sys-typescale-body-small-font);
30
+ font-size: var(--md-sys-typescale-body-small-size);
31
+ line-height: var(--md-sys-typescale-body-small-line-height);
32
+ letter-spacing: var(--md-sys-typescale-body-small-tracking);
33
+ /* Neutral popover-stack ink (matches the overlay surface). */
34
+ color: var(--md-sys-color-inverse-on-surface);
35
+ padding: var(--s-1) var(--s-2);
36
+ text-wrap: pretty;
37
+ }
@@ -0,0 +1,31 @@
1
+ import { LitElement } from "lit";
2
+ import type { TemplateResult } from "lit";
3
+ import type { OverlayPlacement } from "../overlay/index.js";
4
+ export declare class XmTooltip extends LitElement {
5
+ text: string;
6
+ placement: OverlayPlacement;
7
+ openDelay: number;
8
+ open: boolean;
9
+ private _visible;
10
+ private _overlay;
11
+ private _triggerWrap;
12
+ private readonly _labelId;
13
+ private _showTimer;
14
+ disconnectedCallback(): void;
15
+ render(): TemplateResult;
16
+ updated(): void;
17
+ private _wireDescribedBy;
18
+ private get _triggerEl();
19
+ private _onEnter;
20
+ private _onLeave;
21
+ private _onFocusIn;
22
+ private _onFocusOut;
23
+ private _show;
24
+ private _hide;
25
+ private _onOverlayClose;
26
+ }
27
+ declare global {
28
+ interface HTMLElementTagNameMap {
29
+ "xm-tooltip": XmTooltip;
30
+ }
31
+ }
@@ -0,0 +1,196 @@
1
+ /*
2
+ tooltip/index.ts — <xm-tooltip>, a hover/focus contextual label.
3
+
4
+ Composes the xm-overlay foundation (Story 1.4) for anchored positioning and
5
+ top-layer stacking — it does NOT hand-roll anchoring math or z-index. The
6
+ overlay runs in the `tooltip` tier (the LOWEST tier: tooltip < menu < dialog),
7
+ so a tooltip never covers a menu or dialog. We drive the overlay through its
8
+ PUBLIC API only (mode / tier / placement / .anchor / .opener / show / hide /
9
+ xm-overlay-close) and never reach into its shadow root (AD-12).
10
+
11
+ Behaviour (FR-145 / UX-DR6):
12
+ • appears on the trigger being HOVERED or keyboard-FOCUSED
13
+ • dismissed on blur, mouse-leave, and Esc
14
+ • Esc is owned by the overlay's innermost-only handler (stopPropagation),
15
+ so Esc dismisses only the tooltip, never a parent menu/dialog (AD-5a)
16
+
17
+ A11y (UX-DR7): the label gets role="tooltip" + an id; the trigger references it
18
+ via aria-describedby. The tooltip is not focusable and never steals focus.
19
+
20
+ Copy is a neutral, sentence-cased label — NO severity color (AD-11). The
21
+ surface is the inverse-surface popover stack (the overlay owns the chrome).
22
+
23
+ Authoring:
24
+ <xm-tooltip text="Copy to clipboard">
25
+ <xm-button slot="trigger" icon-only aria-label="Copy">…</xm-button>
26
+ </xm-tooltip>
27
+ or with rich label content:
28
+ <xm-tooltip>
29
+ <button slot="trigger">Help</button>
30
+ Opens the keyboard shortcut reference.
31
+ </xm-tooltip>
32
+
33
+ Properties:
34
+ text plain-string label (alternative to the default slot)
35
+ placement overlay placement (default "top")
36
+ open-delay ms before showing on hover (default 100; within motion budget)
37
+ open reflect-only mirror of the visible state (also a preview hook)
38
+
39
+ Shadow DOM. Depends on xm-overlay + tokens (AD-12). Lit is a bare `import` (peer dep).
40
+ */
41
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
42
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
43
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
44
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
45
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
46
+ };
47
+ import { LitElement, html, nothing } from "lit";
48
+ import { customElement, property, query, state } from "lit/decorators.js";
49
+ const TOOLTIP_CSS = new URL("../tooltip/index.css", import.meta.url).href;
50
+ let tooltipSeq = 0;
51
+ let XmTooltip = class XmTooltip extends LitElement {
52
+ constructor() {
53
+ super(...arguments);
54
+ this.text = "";
55
+ this.placement = "top";
56
+ this.openDelay = 100;
57
+ this.open = false;
58
+ this._visible = false;
59
+ this._labelId = `xm-tooltip-${++tooltipSeq}`;
60
+ this._showTimer = 0;
61
+ // Wire the trigger's aria-describedby to the label id so SRs read the tooltip
62
+ // as the trigger's description (the tooltip is not in the tab order).
63
+ this._wireDescribedBy = (e) => {
64
+ const slot = e.target;
65
+ const el = slot.assignedElements()[0];
66
+ if (el)
67
+ el.setAttribute("aria-describedby", this._labelId);
68
+ };
69
+ this._onEnter = () => {
70
+ window.clearTimeout(this._showTimer);
71
+ this._showTimer = window.setTimeout(() => this._show(), this.openDelay);
72
+ };
73
+ this._onLeave = () => {
74
+ window.clearTimeout(this._showTimer);
75
+ this._hide();
76
+ };
77
+ // Keyboard focus shows immediately (no hover delay) so it tracks the caret.
78
+ this._onFocusIn = () => {
79
+ window.clearTimeout(this._showTimer);
80
+ this._show();
81
+ };
82
+ this._onFocusOut = () => {
83
+ window.clearTimeout(this._showTimer);
84
+ this._hide();
85
+ };
86
+ // The overlay owns Esc (innermost-only, stopPropagation). When it self-closes
87
+ // for any reason, sync our state so a later hover re-opens cleanly.
88
+ this._onOverlayClose = () => {
89
+ if (this._visible) {
90
+ this._visible = false;
91
+ this.open = false;
92
+ }
93
+ };
94
+ }
95
+ disconnectedCallback() {
96
+ super.disconnectedCallback();
97
+ window.clearTimeout(this._showTimer);
98
+ }
99
+ render() {
100
+ return html `
101
+ <link rel="stylesheet" href="${TOOLTIP_CSS}" />
102
+ <style>
103
+ :host { display: inline-flex; }
104
+ </style>
105
+ <span
106
+ class="tooltip__trigger"
107
+ @mouseenter=${this._onEnter}
108
+ @mouseleave=${this._onLeave}
109
+ @focusin=${this._onFocusIn}
110
+ @focusout=${this._onFocusOut}
111
+ >
112
+ <slot name="trigger" @slotchange=${this._wireDescribedBy}></slot>
113
+ </span>
114
+
115
+ <xm-overlay
116
+ mode="non-modal"
117
+ tier="tooltip"
118
+ placement=${this.placement}
119
+ @xm-overlay-close=${this._onOverlayClose}
120
+ >
121
+ <div id=${this._labelId} class="tooltip__label" role="tooltip">
122
+ ${this.text ? this.text : html `<slot></slot>`}
123
+ </div>
124
+ </xm-overlay>
125
+ `;
126
+ }
127
+ updated() {
128
+ // Keep the reflected `open` mirror in sync for preview/static hooks.
129
+ if (this.open !== this._visible) {
130
+ if (this.open && !this._visible)
131
+ this._show();
132
+ else if (!this.open && this._visible)
133
+ this._hide();
134
+ }
135
+ }
136
+ get _triggerEl() {
137
+ const slot = this.renderRoot.querySelector('slot[name="trigger"]');
138
+ return slot?.assignedElements()[0] ?? this._triggerWrap;
139
+ }
140
+ _show() {
141
+ if (this._visible)
142
+ return;
143
+ this._visible = true;
144
+ this.open = true;
145
+ this.updateComplete.then(() => {
146
+ // Guard the deferred show: a hover-out (or focusout) before this microtask
147
+ // runs sets `_visible=false`; without this check the queued show() would
148
+ // open a tooltip the component already considers hidden, and no later
149
+ // _hide() could close it (every _hide early-returns on !_visible).
150
+ if (!this._visible)
151
+ return;
152
+ const ov = this._overlay;
153
+ const anchor = this._triggerEl;
154
+ if (ov && anchor) {
155
+ ov.anchor = anchor;
156
+ // The tooltip never steals focus, so do not set .opener (no focus
157
+ // restore needed — focus stays on the trigger throughout).
158
+ ov.show();
159
+ }
160
+ });
161
+ }
162
+ _hide() {
163
+ if (!this._visible)
164
+ return;
165
+ this._visible = false;
166
+ this.open = false;
167
+ const ov = this._overlay;
168
+ if (ov?.open)
169
+ ov.hide("api");
170
+ }
171
+ };
172
+ __decorate([
173
+ property({ type: String })
174
+ ], XmTooltip.prototype, "text", void 0);
175
+ __decorate([
176
+ property({ type: String })
177
+ ], XmTooltip.prototype, "placement", void 0);
178
+ __decorate([
179
+ property({ type: Number, attribute: "open-delay" })
180
+ ], XmTooltip.prototype, "openDelay", void 0);
181
+ __decorate([
182
+ property({ type: Boolean, reflect: true })
183
+ ], XmTooltip.prototype, "open", void 0);
184
+ __decorate([
185
+ state()
186
+ ], XmTooltip.prototype, "_visible", void 0);
187
+ __decorate([
188
+ query("xm-overlay")
189
+ ], XmTooltip.prototype, "_overlay", void 0);
190
+ __decorate([
191
+ query(".tooltip__trigger")
192
+ ], XmTooltip.prototype, "_triggerWrap", void 0);
193
+ XmTooltip = __decorate([
194
+ customElement("xm-tooltip")
195
+ ], XmTooltip);
196
+ export { XmTooltip };