@lumston/ds-angular 0.0.7 → 0.0.8

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 (38) hide show
  1. package/fesm2022/lumston-ds-angular-src-data-display.mjs +215 -0
  2. package/fesm2022/lumston-ds-angular-src-data-display.mjs.map +1 -0
  3. package/fesm2022/lumston-ds-angular-src-dropdown.mjs +94 -0
  4. package/fesm2022/lumston-ds-angular-src-dropdown.mjs.map +1 -0
  5. package/fesm2022/lumston-ds-angular-src-feedback.mjs +400 -0
  6. package/fesm2022/lumston-ds-angular-src-feedback.mjs.map +1 -0
  7. package/fesm2022/lumston-ds-angular-src-icon.mjs +148 -0
  8. package/fesm2022/lumston-ds-angular-src-icon.mjs.map +1 -0
  9. package/fesm2022/lumston-ds-angular-src-inputs.mjs +1132 -0
  10. package/fesm2022/lumston-ds-angular-src-inputs.mjs.map +1 -0
  11. package/fesm2022/lumston-ds-angular-src-navigation.mjs +473 -0
  12. package/fesm2022/lumston-ds-angular-src-navigation.mjs.map +1 -0
  13. package/fesm2022/lumston-ds-angular-src-overlay.mjs +1038 -0
  14. package/fesm2022/lumston-ds-angular-src-overlay.mjs.map +1 -0
  15. package/fesm2022/lumston-ds-angular-src-typography.mjs +303 -0
  16. package/fesm2022/lumston-ds-angular-src-typography.mjs.map +1 -0
  17. package/fesm2022/lumston-ds-angular.mjs +90 -65
  18. package/fesm2022/lumston-ds-angular.mjs.map +1 -1
  19. package/package.json +58 -32
  20. package/styles/index.css +0 -24
  21. package/styles/ls-icons.css +482 -0
  22. package/types/lumston-ds-angular-src-data-display.d.ts +50 -0
  23. package/types/lumston-ds-angular-src-data-display.d.ts.map +1 -0
  24. package/types/lumston-ds-angular-src-dropdown.d.ts +28 -0
  25. package/types/lumston-ds-angular-src-dropdown.d.ts.map +1 -0
  26. package/types/lumston-ds-angular-src-feedback.d.ts +75 -0
  27. package/types/lumston-ds-angular-src-feedback.d.ts.map +1 -0
  28. package/types/lumston-ds-angular-src-icon.d.ts +27 -0
  29. package/types/lumston-ds-angular-src-icon.d.ts.map +1 -0
  30. package/types/lumston-ds-angular-src-inputs.d.ts +201 -0
  31. package/types/lumston-ds-angular-src-inputs.d.ts.map +1 -0
  32. package/types/lumston-ds-angular-src-navigation.d.ts +186 -0
  33. package/types/lumston-ds-angular-src-navigation.d.ts.map +1 -0
  34. package/types/lumston-ds-angular-src-overlay.d.ts +357 -0
  35. package/types/lumston-ds-angular-src-overlay.d.ts.map +1 -0
  36. package/types/lumston-ds-angular-src-typography.d.ts +51 -0
  37. package/types/lumston-ds-angular-src-typography.d.ts.map +1 -0
  38. package/types/lumston-ds-angular.d.ts.map +1 -1
@@ -0,0 +1,1038 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, DestroyRef, model, input, output, viewChild, signal, effect, untracked, HostListener, ChangeDetectionStrategy, Component, computed, ElementRef, Directive, Injectable, contentChild, Renderer2 } from '@angular/core';
3
+ import { DOCUMENT } from '@angular/common';
4
+
5
+ /**
6
+ * Renders an anchored floating menu panel attached to a trigger element.
7
+ *
8
+ * Supports both **controlled** and **directive-driven** open modes:
9
+ * - **Controlled**: bind `[(open)]` and respond to `opened`/`closed` outputs.
10
+ * - **Directive-driven**: apply `lsMenuTriggerFor` to any host element;
11
+ * the directive calls `setAnchorEl()` and `toggle()` automatically.
12
+ *
13
+ * Panel position is derived from the anchor element's bounding rect combined
14
+ * with `anchorOrigin` (attachment point on the trigger) and `transformOrigin`
15
+ * (attachment point on the panel). Position is recomputed each time the
16
+ * panel opens via a `setTimeout(0)` deferral to ensure the panel is measured.
17
+ *
18
+ * When `disablePortal` is `false` (default), the panel uses `position: fixed`
19
+ * for viewport-relative placement. When `true`, it uses `position: absolute`.
20
+ *
21
+ * Keyboard: `Escape` closes the panel; `ArrowDown`/`ArrowUp` move focus
22
+ * between enabled `[role="menuitem"]` elements inside the panel.
23
+ *
24
+ * @example
25
+ * ```html
26
+ * <!-- Controlled -->
27
+ * <ls-menu [(open)]="isOpen" [anchorEl]="triggerEl">
28
+ * <ls-menu-item (itemClick)="onEdit()">Edit</ls-menu-item>
29
+ * </ls-menu>
30
+ *
31
+ * <!-- Directive-driven -->
32
+ * <button [lsMenuTriggerFor]="myMenu">Open</button>
33
+ * <ls-menu #myMenu>
34
+ * <ls-menu-item>Delete</ls-menu-item>
35
+ * </ls-menu>
36
+ * ```
37
+ */
38
+ class MenuComponent {
39
+ constructor() {
40
+ this._document = inject(DOCUMENT);
41
+ this._destroyRef = inject(DestroyRef);
42
+ /** Controls the visibility of the menu panel. Supports two-way binding. */
43
+ this.open = model(false, ...(ngDevMode ? [{ debugName: "open" }] : []));
44
+ /**
45
+ * Element used to position the menu panel.
46
+ *
47
+ * Accepts a native DOM element, an `ElementRef`, or any Angular component
48
+ * that exposes a `nativeElement: HTMLElement` property (e.g. `ls-button`).
49
+ * In templates, pass a template reference variable directly:
50
+ * `[anchorEl]="btn"` where `#btn` is on any element or component.
51
+ *
52
+ * When using `lsMenuTriggerFor`, this is set automatically by the directive
53
+ * via `setAnchorEl()`. When using controlled mode, bind directly.
54
+ *
55
+ * @default null
56
+ */
57
+ this.anchorEl = input(null, ...(ngDevMode ? [{ debugName: "anchorEl" }] : []));
58
+ /**
59
+ * Defines the attachment point on the anchor element.
60
+ *
61
+ * Combined with `transformOrigin` to compute the panel's `top`/`left`
62
+ * position via `getBoundingClientRect()`.
63
+ *
64
+ * @default { vertical: 'bottom', horizontal: 'left' }
65
+ */
66
+ this.anchorOrigin = input({
67
+ vertical: 'bottom',
68
+ horizontal: 'left',
69
+ }, ...(ngDevMode ? [{ debugName: "anchorOrigin" }] : []));
70
+ /**
71
+ * Defines the attachment point on the menu panel surface.
72
+ *
73
+ * The panel is translated so this point aligns with `anchorOrigin`.
74
+ *
75
+ * @default { vertical: 'top', horizontal: 'left' }
76
+ */
77
+ this.transformOrigin = input({
78
+ vertical: 'top',
79
+ horizontal: 'left',
80
+ }, ...(ngDevMode ? [{ debugName: "transformOrigin" }] : []));
81
+ /**
82
+ * When `false` (default), the panel uses `position: fixed` for
83
+ * viewport-relative placement. When `true`, uses `position: absolute`
84
+ * and renders relative to the nearest positioned ancestor.
85
+ *
86
+ * @default false
87
+ */
88
+ this.disablePortal = input(false, ...(ngDevMode ? [{ debugName: "disablePortal" }] : []));
89
+ /**
90
+ * When `true`, the panel closes automatically after the user activates
91
+ * a `ls-menu-item` (i.e., a `[role="menuitem"]` element) inside it.
92
+ *
93
+ * @default true
94
+ */
95
+ this.closeOnClick = input(true, ...(ngDevMode ? [{ debugName: "closeOnClick" }] : []));
96
+ /**
97
+ * Emits when the panel's opening animation completes.
98
+ * Does NOT emit when `open` is set programmatically without animation.
99
+ */
100
+ this.opened = output();
101
+ /**
102
+ * Emits when the panel's closing animation completes and the panel
103
+ * is fully hidden. In controlled mode, the host can use this to update
104
+ * state after the transition finishes.
105
+ */
106
+ this.closed = output();
107
+ /**
108
+ * Emits when the user clicks the transparent backdrop behind the panel.
109
+ * The menu closes automatically after this output emits.
110
+ */
111
+ this.backdropClick = output();
112
+ this._panelRef = viewChild('panelRef', ...(ngDevMode ? [{ debugName: "_panelRef" }] : []));
113
+ this._isAnimating = signal(false, ...(ngDevMode ? [{ debugName: "_isAnimating" }] : []));
114
+ this._wasOpen = false;
115
+ this._previouslyFocused = null;
116
+ this._savedBodyOverflow = '';
117
+ this._savedBodyPaddingRight = '';
118
+ this._resolvedAnchorEl = signal(null, ...(ngDevMode ? [{ debugName: "_resolvedAnchorEl" }] : []));
119
+ this._repositionHandler = () => this._computeAndApplyPosition();
120
+ // Manages animation state, scroll lock, focus, and repositioning listeners
121
+ // when the panel opens or closes.
122
+ effect(() => {
123
+ const isOpen = this.open();
124
+ untracked(() => {
125
+ if (isOpen) {
126
+ this._isAnimating.set(true);
127
+ this._previouslyFocused = this._document.activeElement;
128
+ this._savedBodyOverflow = this._document.body.style.overflow;
129
+ this._savedBodyPaddingRight = this._document.body.style.paddingRight;
130
+ const scrollbarWidth = this._getScrollbarWidth();
131
+ if (scrollbarWidth > 0) {
132
+ this._document.body.style.paddingRight = `${scrollbarWidth}px`;
133
+ }
134
+ this._document.body.style.overflow = 'hidden';
135
+ setTimeout(() => this._panelRef()?.nativeElement.focus(), 0);
136
+ window.addEventListener('resize', this._repositionHandler);
137
+ window.addEventListener('scroll', this._repositionHandler, true);
138
+ this._wasOpen = true;
139
+ }
140
+ else if (this._wasOpen) {
141
+ this._isAnimating.set(true);
142
+ window.removeEventListener('resize', this._repositionHandler);
143
+ window.removeEventListener('scroll', this._repositionHandler, true);
144
+ this._wasOpen = false;
145
+ }
146
+ });
147
+ });
148
+ // Computes and applies panel position whenever the panel enters the DOM
149
+ // or any positioning input changes. Using a separate effect (rather than
150
+ // setTimeout) guarantees that Angular has already updated the viewChild
151
+ // signal before this runs, so _panelRef() is always non-null here.
152
+ effect(() => {
153
+ const panel = this._panelRef()?.nativeElement;
154
+ if (!panel)
155
+ return;
156
+ this._computeAndApplyPosition();
157
+ });
158
+ this._destroyRef.onDestroy(() => {
159
+ window.removeEventListener('resize', this._repositionHandler);
160
+ window.removeEventListener('scroll', this._repositionHandler, true);
161
+ if (this._wasOpen) {
162
+ this._document.body.style.overflow = this._savedBodyOverflow;
163
+ this._document.body.style.paddingRight = this._savedBodyPaddingRight;
164
+ this._previouslyFocused?.focus?.();
165
+ }
166
+ });
167
+ }
168
+ /** Toggles the panel between open and closed. */
169
+ toggle() {
170
+ this.open.set(!this.open());
171
+ }
172
+ /**
173
+ * Sets the anchor element used for panel positioning.
174
+ * Called automatically by `MenuTriggerDirective`.
175
+ */
176
+ setAnchorEl(el) {
177
+ this._resolvedAnchorEl.set(el);
178
+ }
179
+ /** Closes the panel without waiting for a user interaction. */
180
+ requestClose() {
181
+ this.open.set(false);
182
+ }
183
+ onBackdropClick(event) {
184
+ this.backdropClick.emit(event);
185
+ this.open.set(false);
186
+ }
187
+ onPanelClick(event) {
188
+ if (!this.closeOnClick())
189
+ return;
190
+ const target = event.target;
191
+ if (target.closest('[role="menuitem"]') !== null) {
192
+ this.open.set(false);
193
+ }
194
+ }
195
+ onAnimationEnd() {
196
+ this._isAnimating.set(false);
197
+ if (this.open()) {
198
+ this.opened.emit();
199
+ }
200
+ else {
201
+ this._document.body.style.overflow = this._savedBodyOverflow;
202
+ this._document.body.style.paddingRight = this._savedBodyPaddingRight;
203
+ this.closed.emit();
204
+ this._previouslyFocused?.focus?.();
205
+ this._previouslyFocused = null;
206
+ }
207
+ }
208
+ onEscape() {
209
+ if (this.open()) {
210
+ this.open.set(false);
211
+ }
212
+ }
213
+ onArrowDown(event) {
214
+ if (!this.open())
215
+ return;
216
+ event.preventDefault();
217
+ this._moveFocus(1);
218
+ }
219
+ onArrowUp(event) {
220
+ if (!this.open())
221
+ return;
222
+ event.preventDefault();
223
+ this._moveFocus(-1);
224
+ }
225
+ _computeAndApplyPosition() {
226
+ const rawAnchor = this.anchorEl() ?? this._resolvedAnchorEl();
227
+ const panel = this._panelRef()?.nativeElement;
228
+ if (!rawAnchor || !panel)
229
+ return;
230
+ const anchorEl = this._toHTMLElement(rawAnchor);
231
+ if (!anchorEl)
232
+ return;
233
+ const anchorRect = anchorEl.getBoundingClientRect();
234
+ const panelRect = panel.getBoundingClientRect();
235
+ const ao = this.anchorOrigin();
236
+ const to = this.transformOrigin();
237
+ const anchorX = anchorRect.left +
238
+ (ao.horizontal === 'center'
239
+ ? anchorRect.width / 2
240
+ : ao.horizontal === 'right'
241
+ ? anchorRect.width
242
+ : 0);
243
+ const anchorY = anchorRect.top +
244
+ (ao.vertical === 'center'
245
+ ? anchorRect.height / 2
246
+ : ao.vertical === 'bottom'
247
+ ? anchorRect.height
248
+ : 0);
249
+ const transformX = to.horizontal === 'center'
250
+ ? panelRect.width / 2
251
+ : to.horizontal === 'right'
252
+ ? panelRect.width
253
+ : 0;
254
+ const transformY = to.vertical === 'center'
255
+ ? panelRect.height / 2
256
+ : to.vertical === 'bottom'
257
+ ? panelRect.height
258
+ : 0;
259
+ panel.style.setProperty('--menu-top', `${anchorY - transformY}px`);
260
+ panel.style.setProperty('--menu-left', `${anchorX - transformX}px`);
261
+ }
262
+ /**
263
+ * Resolves any supported anchor value to a plain `HTMLElement`.
264
+ *
265
+ * Handles: `HTMLElement`, `ElementRef<HTMLElement>`, and objects that expose
266
+ * a `nativeElement: HTMLElement` property (e.g. `ls-button` component refs).
267
+ */
268
+ _toHTMLElement(anchor) {
269
+ if (!anchor)
270
+ return null;
271
+ if (anchor instanceof HTMLElement)
272
+ return anchor;
273
+ if (typeof anchor === 'object' &&
274
+ anchor !== null &&
275
+ 'nativeElement' in anchor) {
276
+ const el = anchor.nativeElement;
277
+ return el instanceof HTMLElement ? el : null;
278
+ }
279
+ return null;
280
+ }
281
+ _moveFocus(direction) {
282
+ const panel = this._panelRef()?.nativeElement;
283
+ if (!panel)
284
+ return;
285
+ const items = Array.from(panel.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])'));
286
+ if (items.length === 0)
287
+ return;
288
+ const currentIndex = items.indexOf(this._document.activeElement);
289
+ const nextIndex = currentIndex === -1
290
+ ? direction === 1
291
+ ? 0
292
+ : items.length - 1
293
+ : (currentIndex + direction + items.length) % items.length;
294
+ items[nextIndex]?.focus();
295
+ }
296
+ _getScrollbarWidth() {
297
+ return window.innerWidth - this._document.documentElement.clientWidth;
298
+ }
299
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
300
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: MenuComponent, isStandalone: true, selector: "ls-menu", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, anchorEl: { classPropertyName: "anchorEl", publicName: "anchorEl", isSignal: true, isRequired: false, transformFunction: null }, anchorOrigin: { classPropertyName: "anchorOrigin", publicName: "anchorOrigin", isSignal: true, isRequired: false, transformFunction: null }, transformOrigin: { classPropertyName: "transformOrigin", publicName: "transformOrigin", isSignal: true, isRequired: false, transformFunction: null }, disablePortal: { classPropertyName: "disablePortal", publicName: "disablePortal", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", opened: "opened", closed: "closed", backdropClick: "backdropClick" }, host: { listeners: { "document:keydown.escape": "onEscape()", "document:keydown.arrowdown": "onArrowDown($event)", "document:keydown.arrowup": "onArrowUp($event)" } }, viewQueries: [{ propertyName: "_panelRef", first: true, predicate: ["panelRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
301
+ @if (open() || _isAnimating()) {
302
+ <div class="menu-backdrop" (click)="onBackdropClick($event)"></div>
303
+ <div
304
+ #panelRef
305
+ class="menu-panel"
306
+ [class.menu-panel-inline]="disablePortal()"
307
+ [class.menu-enter]="open() && _isAnimating()"
308
+ [class.menu-leave]="!open() && _isAnimating()"
309
+ role="menu"
310
+ tabindex="-1"
311
+ (click)="onPanelClick($event)"
312
+ (animationend)="onAnimationEnd()">
313
+ <ng-content />
314
+ </div>
315
+ }
316
+ `, isInline: true, styles: [":host{display:contents}.menu-backdrop{position:fixed;inset:0;z-index:var(--ls-menu-z-index);background-color:transparent}.menu-panel{position:fixed;top:var(--menu-top, 0px);left:var(--menu-left, 0px);z-index:calc(var(--ls-menu-z-index) + 1);min-width:10rem;padding:.25rem 0;background-color:#fff;border-radius:var(--ls-border-radius-md);box-shadow:0 4px 24px #0000001f;outline:none}.menu-panel.menu-panel-inline{position:absolute}@keyframes menu-enter-kf{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes menu-leave-kf{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.95) translateY(-4px)}}.menu-panel.menu-enter{animation:menu-enter-kf .15s ease-out forwards}.menu-panel.menu-leave{animation:menu-leave-kf .1s ease-in forwards}.menu-item{display:flex;align-items:center;width:100%;padding:.5rem 1rem;background:none;border:none;text-align:left;font-family:var(--ls-font-family);font-size:.875rem;color:#3b3f5c;cursor:pointer;transition:background-color var(--ls-transition-duration) ease}.menu-item:hover:not(:disabled){background-color:#f1f2f3}.menu-item:focus-visible{outline:2px solid var(--ls-color-primary);outline-offset:-2px;background-color:#f1f2f3}.menu-item-dense{padding-top:.25rem;padding-bottom:.25rem}.menu-item-no-gutters{padding-inline:0}.menu-item-divider{border-bottom:1px solid #e0e6ed}.menu-item-disabled{color:#888ea8;pointer-events:none;cursor:not-allowed}body.dark .menu-panel{background-color:#1b2e4b;box-shadow:0 4px 24px #0006}body.dark .menu-item{color:#e0e6ed}body.dark .menu-item:hover:not(:disabled){background-color:#253b5e}body.dark .menu-item:focus-visible{background-color:#253b5e}body.dark .menu-item-divider{border-bottom-color:#253b5e}body.dark .menu-item-disabled{color:#506690}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
317
+ }
318
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MenuComponent, decorators: [{
319
+ type: Component,
320
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, imports: [], selector: 'ls-menu', standalone: true, template: `
321
+ @if (open() || _isAnimating()) {
322
+ <div class="menu-backdrop" (click)="onBackdropClick($event)"></div>
323
+ <div
324
+ #panelRef
325
+ class="menu-panel"
326
+ [class.menu-panel-inline]="disablePortal()"
327
+ [class.menu-enter]="open() && _isAnimating()"
328
+ [class.menu-leave]="!open() && _isAnimating()"
329
+ role="menu"
330
+ tabindex="-1"
331
+ (click)="onPanelClick($event)"
332
+ (animationend)="onAnimationEnd()">
333
+ <ng-content />
334
+ </div>
335
+ }
336
+ `, styles: [":host{display:contents}.menu-backdrop{position:fixed;inset:0;z-index:var(--ls-menu-z-index);background-color:transparent}.menu-panel{position:fixed;top:var(--menu-top, 0px);left:var(--menu-left, 0px);z-index:calc(var(--ls-menu-z-index) + 1);min-width:10rem;padding:.25rem 0;background-color:#fff;border-radius:var(--ls-border-radius-md);box-shadow:0 4px 24px #0000001f;outline:none}.menu-panel.menu-panel-inline{position:absolute}@keyframes menu-enter-kf{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes menu-leave-kf{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.95) translateY(-4px)}}.menu-panel.menu-enter{animation:menu-enter-kf .15s ease-out forwards}.menu-panel.menu-leave{animation:menu-leave-kf .1s ease-in forwards}.menu-item{display:flex;align-items:center;width:100%;padding:.5rem 1rem;background:none;border:none;text-align:left;font-family:var(--ls-font-family);font-size:.875rem;color:#3b3f5c;cursor:pointer;transition:background-color var(--ls-transition-duration) ease}.menu-item:hover:not(:disabled){background-color:#f1f2f3}.menu-item:focus-visible{outline:2px solid var(--ls-color-primary);outline-offset:-2px;background-color:#f1f2f3}.menu-item-dense{padding-top:.25rem;padding-bottom:.25rem}.menu-item-no-gutters{padding-inline:0}.menu-item-divider{border-bottom:1px solid #e0e6ed}.menu-item-disabled{color:#888ea8;pointer-events:none;cursor:not-allowed}body.dark .menu-panel{background-color:#1b2e4b;box-shadow:0 4px 24px #0006}body.dark .menu-item{color:#e0e6ed}body.dark .menu-item:hover:not(:disabled){background-color:#253b5e}body.dark .menu-item:focus-visible{background-color:#253b5e}body.dark .menu-item-divider{border-bottom-color:#253b5e}body.dark .menu-item-disabled{color:#506690}\n"] }]
337
+ }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], anchorEl: [{ type: i0.Input, args: [{ isSignal: true, alias: "anchorEl", required: false }] }], anchorOrigin: [{ type: i0.Input, args: [{ isSignal: true, alias: "anchorOrigin", required: false }] }], transformOrigin: [{ type: i0.Input, args: [{ isSignal: true, alias: "transformOrigin", required: false }] }], disablePortal: [{ type: i0.Input, args: [{ isSignal: true, alias: "disablePortal", required: false }] }], closeOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClick", required: false }] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], backdropClick: [{ type: i0.Output, args: ["backdropClick"] }], _panelRef: [{ type: i0.ViewChild, args: ['panelRef', { isSignal: true }] }], onEscape: [{
338
+ type: HostListener,
339
+ args: ['document:keydown.escape']
340
+ }], onArrowDown: [{
341
+ type: HostListener,
342
+ args: ['document:keydown.arrowdown', ['$event']]
343
+ }], onArrowUp: [{
344
+ type: HostListener,
345
+ args: ['document:keydown.arrowup', ['$event']]
346
+ }] } });
347
+
348
+ /**
349
+ * Interactive item rendered inside an `ls-menu` panel.
350
+ *
351
+ * Renders a `<button role="menuitem">` that projects its label via
352
+ * `<ng-content>`. Visual density, gutters, and a bottom divider are
353
+ * configurable via inputs. When `disabled` is `true`, the item is not
354
+ * interactive and the `itemClick` output will not emit.
355
+ *
356
+ * @example
357
+ * ```html
358
+ * <ls-menu-item [dense]="true" (itemClick)="onEdit($event)">
359
+ * Edit
360
+ * </ls-menu-item>
361
+ * ```
362
+ */
363
+ class MenuItemComponent {
364
+ constructor() {
365
+ /**
366
+ * Reduces the vertical padding of the item for compact layouts.
367
+ *
368
+ * @default false
369
+ */
370
+ this.dense = input(false, ...(ngDevMode ? [{ debugName: "dense" }] : []));
371
+ /**
372
+ * Removes left and right padding when `true`.
373
+ *
374
+ * @default false
375
+ */
376
+ this.disableGutters = input(false, ...(ngDevMode ? [{ debugName: "disableGutters" }] : []));
377
+ /**
378
+ * Adds a 1px border at the bottom of the item to act as a visual divider.
379
+ *
380
+ * @default false
381
+ */
382
+ this.divider = input(false, ...(ngDevMode ? [{ debugName: "divider" }] : []));
383
+ /**
384
+ * Prevents interaction. Applies disabled styling, sets `aria-disabled="true"`,
385
+ * and suppresses the `itemClick` output.
386
+ *
387
+ * @default false
388
+ */
389
+ this.disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
390
+ /**
391
+ * Emits the originating `MouseEvent` when the user activates the item.
392
+ * Does NOT emit when `disabled` is `true`.
393
+ */
394
+ this.itemClick = output();
395
+ this._itemClasses = computed(() => {
396
+ const classes = ['menu-item'];
397
+ if (this.dense())
398
+ classes.push('menu-item-dense');
399
+ if (this.disableGutters())
400
+ classes.push('menu-item-no-gutters');
401
+ if (this.divider())
402
+ classes.push('menu-item-divider');
403
+ if (this.disabled())
404
+ classes.push('menu-item-disabled');
405
+ return classes.join(' ');
406
+ }, ...(ngDevMode ? [{ debugName: "_itemClasses" }] : []));
407
+ }
408
+ handleClick(event) {
409
+ if (this.disabled())
410
+ return;
411
+ this.itemClick.emit(event);
412
+ }
413
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MenuItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
414
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.2", type: MenuItemComponent, isStandalone: true, selector: "ls-menu-item", inputs: { dense: { classPropertyName: "dense", publicName: "dense", isSignal: true, isRequired: false, transformFunction: null }, disableGutters: { classPropertyName: "disableGutters", publicName: "disableGutters", isSignal: true, isRequired: false, transformFunction: null }, divider: { classPropertyName: "divider", publicName: "divider", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick" }, ngImport: i0, template: `
415
+ <button
416
+ type="button"
417
+ [class]="_itemClasses()"
418
+ [disabled]="disabled()"
419
+ [attr.aria-disabled]="disabled() ? 'true' : null"
420
+ role="menuitem"
421
+ (click)="handleClick($event)">
422
+ <ng-content />
423
+ </button>
424
+ `, isInline: true, styles: [":host{display:contents}.menu-backdrop{position:fixed;inset:0;z-index:var(--ls-menu-z-index);background-color:transparent}.menu-panel{position:fixed;top:var(--menu-top, 0px);left:var(--menu-left, 0px);z-index:calc(var(--ls-menu-z-index) + 1);min-width:10rem;padding:.25rem 0;background-color:#fff;border-radius:var(--ls-border-radius-md);box-shadow:0 4px 24px #0000001f;outline:none}.menu-panel.menu-panel-inline{position:absolute}@keyframes menu-enter-kf{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes menu-leave-kf{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.95) translateY(-4px)}}.menu-panel.menu-enter{animation:menu-enter-kf .15s ease-out forwards}.menu-panel.menu-leave{animation:menu-leave-kf .1s ease-in forwards}.menu-item{display:flex;align-items:center;width:100%;padding:.5rem 1rem;background:none;border:none;text-align:left;font-family:var(--ls-font-family);font-size:.875rem;color:#3b3f5c;cursor:pointer;transition:background-color var(--ls-transition-duration) ease}.menu-item:hover:not(:disabled){background-color:#f1f2f3}.menu-item:focus-visible{outline:2px solid var(--ls-color-primary);outline-offset:-2px;background-color:#f1f2f3}.menu-item-dense{padding-top:.25rem;padding-bottom:.25rem}.menu-item-no-gutters{padding-inline:0}.menu-item-divider{border-bottom:1px solid #e0e6ed}.menu-item-disabled{color:#888ea8;pointer-events:none;cursor:not-allowed}body.dark .menu-panel{background-color:#1b2e4b;box-shadow:0 4px 24px #0006}body.dark .menu-item{color:#e0e6ed}body.dark .menu-item:hover:not(:disabled){background-color:#253b5e}body.dark .menu-item:focus-visible{background-color:#253b5e}body.dark .menu-item-divider{border-bottom-color:#253b5e}body.dark .menu-item-disabled{color:#506690}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
425
+ }
426
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MenuItemComponent, decorators: [{
427
+ type: Component,
428
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, imports: [], selector: 'ls-menu-item', standalone: true, template: `
429
+ <button
430
+ type="button"
431
+ [class]="_itemClasses()"
432
+ [disabled]="disabled()"
433
+ [attr.aria-disabled]="disabled() ? 'true' : null"
434
+ role="menuitem"
435
+ (click)="handleClick($event)">
436
+ <ng-content />
437
+ </button>
438
+ `, styles: [":host{display:contents}.menu-backdrop{position:fixed;inset:0;z-index:var(--ls-menu-z-index);background-color:transparent}.menu-panel{position:fixed;top:var(--menu-top, 0px);left:var(--menu-left, 0px);z-index:calc(var(--ls-menu-z-index) + 1);min-width:10rem;padding:.25rem 0;background-color:#fff;border-radius:var(--ls-border-radius-md);box-shadow:0 4px 24px #0000001f;outline:none}.menu-panel.menu-panel-inline{position:absolute}@keyframes menu-enter-kf{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes menu-leave-kf{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.95) translateY(-4px)}}.menu-panel.menu-enter{animation:menu-enter-kf .15s ease-out forwards}.menu-panel.menu-leave{animation:menu-leave-kf .1s ease-in forwards}.menu-item{display:flex;align-items:center;width:100%;padding:.5rem 1rem;background:none;border:none;text-align:left;font-family:var(--ls-font-family);font-size:.875rem;color:#3b3f5c;cursor:pointer;transition:background-color var(--ls-transition-duration) ease}.menu-item:hover:not(:disabled){background-color:#f1f2f3}.menu-item:focus-visible{outline:2px solid var(--ls-color-primary);outline-offset:-2px;background-color:#f1f2f3}.menu-item-dense{padding-top:.25rem;padding-bottom:.25rem}.menu-item-no-gutters{padding-inline:0}.menu-item-divider{border-bottom:1px solid #e0e6ed}.menu-item-disabled{color:#888ea8;pointer-events:none;cursor:not-allowed}body.dark .menu-panel{background-color:#1b2e4b;box-shadow:0 4px 24px #0006}body.dark .menu-item{color:#e0e6ed}body.dark .menu-item:hover:not(:disabled){background-color:#253b5e}body.dark .menu-item:focus-visible{background-color:#253b5e}body.dark .menu-item-divider{border-bottom-color:#253b5e}body.dark .menu-item-disabled{color:#506690}\n"] }]
439
+ }], propDecorators: { dense: [{ type: i0.Input, args: [{ isSignal: true, alias: "dense", required: false }] }], disableGutters: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableGutters", required: false }] }], divider: [{ type: i0.Input, args: [{ isSignal: true, alias: "divider", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }] } });
440
+
441
+ /**
442
+ * Connects any host element to a `MenuComponent` instance, enabling
443
+ * click-to-toggle behavior without manual open-state management.
444
+ *
445
+ * Sets `anchorEl` on the linked `MenuComponent` to the host element
446
+ * before toggling visibility, so the panel is correctly positioned
447
+ * relative to the trigger. Also applies `aria-haspopup="menu"` to the
448
+ * host for accessibility.
449
+ *
450
+ * @example
451
+ * ```html
452
+ * <button type="button" [lsMenuTriggerFor]="myMenu">Options</button>
453
+ * <ls-menu #myMenu>
454
+ * <ls-menu-item>Delete</ls-menu-item>
455
+ * </ls-menu>
456
+ * ```
457
+ */
458
+ class MenuTriggerDirective {
459
+ constructor() {
460
+ /**
461
+ * The `MenuComponent` instance this directive controls.
462
+ * Assign a template reference variable of `ls-menu`.
463
+ */
464
+ this.lsMenuTriggerFor = input.required(...(ngDevMode ? [{ debugName: "lsMenuTriggerFor" }] : []));
465
+ this._elementRef = inject((ElementRef));
466
+ }
467
+ onClick() {
468
+ const menu = this.lsMenuTriggerFor();
469
+ menu.setAnchorEl(this._resolveAnchorElement());
470
+ menu.toggle();
471
+ }
472
+ /**
473
+ * Resolves the first ancestor element that has a real layout box.
474
+ *
475
+ * Angular component hosts commonly use `:host { display: contents }`,
476
+ * which means the element itself has no bounding box and
477
+ * `getBoundingClientRect()` returns all zeros. This method walks down
478
+ * through `display: contents` wrappers until it reaches the first child
479
+ * that participates in layout, so the menu panel is positioned relative
480
+ * to the visible trigger element rather than a phantom box.
481
+ */
482
+ _resolveAnchorElement() {
483
+ let el = this._elementRef.nativeElement;
484
+ while (el.firstElementChild && getComputedStyle(el).display === 'contents') {
485
+ el = el.firstElementChild;
486
+ }
487
+ return el;
488
+ }
489
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MenuTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
490
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.2", type: MenuTriggerDirective, isStandalone: true, selector: "[lsMenuTriggerFor]", inputs: { lsMenuTriggerFor: { classPropertyName: "lsMenuTriggerFor", publicName: "lsMenuTriggerFor", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "aria-haspopup": "menu" }, listeners: { "click": "onClick()" } }, ngImport: i0 }); }
491
+ }
492
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MenuTriggerDirective, decorators: [{
493
+ type: Directive,
494
+ args: [{
495
+ host: { 'aria-haspopup': 'menu' },
496
+ selector: '[lsMenuTriggerFor]',
497
+ standalone: true,
498
+ }]
499
+ }], propDecorators: { lsMenuTriggerFor: [{ type: i0.Input, args: [{ isSignal: true, alias: "lsMenuTriggerFor", required: true }] }], onClick: [{
500
+ type: HostListener,
501
+ args: ['click']
502
+ }] } });
503
+
504
+ class ModalActionsComponent {
505
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ModalActionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
506
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: ModalActionsComponent, isStandalone: true, selector: "ls-modal-actions", host: { classAttribute: "modal-actions" }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
507
+ }
508
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ModalActionsComponent, decorators: [{
509
+ type: Component,
510
+ args: [{
511
+ changeDetection: ChangeDetectionStrategy.OnPush,
512
+ host: { class: 'modal-actions' },
513
+ imports: [],
514
+ selector: 'ls-modal-actions',
515
+ standalone: true,
516
+ template: `<ng-content />`,
517
+ }]
518
+ }] });
519
+
520
+ let _titleIdCounter = 0;
521
+ class ModalTitleComponent {
522
+ constructor() {
523
+ this.id = `ls-modal-title-${++_titleIdCounter}`;
524
+ }
525
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ModalTitleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
526
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: ModalTitleComponent, isStandalone: true, selector: "ls-modal-title", host: { properties: { "id": "id" }, classAttribute: "modal-title" }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
527
+ }
528
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ModalTitleComponent, decorators: [{
529
+ type: Component,
530
+ args: [{
531
+ changeDetection: ChangeDetectionStrategy.OnPush,
532
+ host: { class: 'modal-title', '[id]': 'id' },
533
+ imports: [],
534
+ selector: 'ls-modal-title',
535
+ standalone: true,
536
+ template: `<ng-content />`,
537
+ }]
538
+ }] });
539
+
540
+ class ModalStackService {
541
+ constructor() {
542
+ this._stack = signal([], ...(ngDevMode ? [{ debugName: "_stack" }] : []));
543
+ }
544
+ push(id) {
545
+ this._stack.update(stack => [...stack, id]);
546
+ }
547
+ pop(id) {
548
+ this._stack.update(stack => stack.filter(s => s !== id));
549
+ }
550
+ isTop(id) {
551
+ const stack = this._stack();
552
+ return stack.length > 0 && stack[stack.length - 1] === id;
553
+ }
554
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ModalStackService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
555
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ModalStackService, providedIn: 'root' }); }
556
+ }
557
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ModalStackService, decorators: [{
558
+ type: Injectable,
559
+ args: [{ providedIn: 'root' }]
560
+ }] });
561
+
562
+ let _modalIdCounter = 0;
563
+ class ModalComponent {
564
+ constructor() {
565
+ this.open = input(false, ...(ngDevMode ? [{ debugName: "open" }] : []));
566
+ this.disableBackdropClose = input(false, ...(ngDevMode ? [{ debugName: "disableBackdropClose" }] : []));
567
+ this.fullScreen = input(false, ...(ngDevMode ? [{ debugName: "fullScreen" }] : []));
568
+ this.fullWidth = input(false, ...(ngDevMode ? [{ debugName: "fullWidth" }] : []));
569
+ this.maxWidth = input('md', ...(ngDevMode ? [{ debugName: "maxWidth" }] : []));
570
+ this.scroll = input('dialog', ...(ngDevMode ? [{ debugName: "scroll" }] : []));
571
+ this.showCloseButton = input(true, ...(ngDevMode ? [{ debugName: "showCloseButton" }] : []));
572
+ this.closed = output();
573
+ this._modalStackService = inject(ModalStackService);
574
+ this._titleComponent = contentChild(ModalTitleComponent, ...(ngDevMode ? [{ debugName: "_titleComponent" }] : []));
575
+ this._panel = viewChild('panel', ...(ngDevMode ? [{ debugName: "_panel" }] : []));
576
+ this._id = `ls-modal-${++_modalIdCounter}`;
577
+ this._previouslyFocused = null;
578
+ this.labelledById = computed(() => {
579
+ const title = this._titleComponent();
580
+ return title ? title.id : null;
581
+ }, ...(ngDevMode ? [{ debugName: "labelledById" }] : []));
582
+ this.overlayClasses = computed(() => {
583
+ const classes = ['modal-overlay'];
584
+ if (this.scroll() === 'body')
585
+ classes.push('modal-overlay-body');
586
+ return classes.join(' ');
587
+ }, ...(ngDevMode ? [{ debugName: "overlayClasses" }] : []));
588
+ this.panelClasses = computed(() => {
589
+ const classes = [
590
+ 'modal-panel',
591
+ `modal-max-${this.maxWidth()}`,
592
+ `modal-scroll-${this.scroll()}`,
593
+ ];
594
+ if (this.fullScreen())
595
+ classes.push('modal-full-screen');
596
+ if (this.fullWidth())
597
+ classes.push('modal-full-width');
598
+ if (this.showCloseButton())
599
+ classes.push('modal-has-close-btn');
600
+ return classes.join(' ');
601
+ }, ...(ngDevMode ? [{ debugName: "panelClasses" }] : []));
602
+ effect(() => {
603
+ if (this.open()) {
604
+ this._previouslyFocused = document.activeElement;
605
+ this._modalStackService.push(this._id);
606
+ setTimeout(() => {
607
+ untracked(() => this._panel()?.nativeElement.focus());
608
+ }, 0);
609
+ }
610
+ else {
611
+ this._modalStackService.pop(this._id);
612
+ this._previouslyFocused?.focus?.();
613
+ this._previouslyFocused = null;
614
+ }
615
+ });
616
+ }
617
+ ngOnDestroy() {
618
+ if (this.open()) {
619
+ this._modalStackService.pop(this._id);
620
+ }
621
+ }
622
+ onEscape() {
623
+ if (this.open() && this._modalStackService.isTop(this._id)) {
624
+ this.closed.emit();
625
+ }
626
+ }
627
+ onBackdropClick() {
628
+ if (!this.disableBackdropClose()) {
629
+ this.closed.emit();
630
+ }
631
+ }
632
+ onCloseButtonClick() {
633
+ this.closed.emit();
634
+ }
635
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
636
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: ModalComponent, isStandalone: true, selector: "ls-modal", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, disableBackdropClose: { classPropertyName: "disableBackdropClose", publicName: "disableBackdropClose", isSignal: true, isRequired: false, transformFunction: null }, fullScreen: { classPropertyName: "fullScreen", publicName: "fullScreen", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, scroll: { classPropertyName: "scroll", publicName: "scroll", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, host: { listeners: { "document:keydown.escape": "onEscape()" } }, queries: [{ propertyName: "_titleComponent", first: true, predicate: ModalTitleComponent, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "_panel", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: `
637
+ @if (open()) {
638
+ <div [class]="overlayClasses()" (click)="onBackdropClick()">
639
+ <div
640
+ #panel
641
+ [attr.aria-labelledby]="labelledById()"
642
+ [attr.aria-modal]="true"
643
+ [class]="panelClasses()"
644
+ role="dialog"
645
+ tabindex="-1"
646
+ (click)="$event.stopPropagation()">
647
+ @if (showCloseButton()) {
648
+ <button
649
+ aria-label="Close"
650
+ class="modal-close-btn"
651
+ type="button"
652
+ (click)="onCloseButtonClick()">
653
+ <i class="ls-icon ls-x ls-icon-sm"></i>
654
+ </button>
655
+ }
656
+ <ng-content />
657
+ </div>
658
+ </div>
659
+ }
660
+ `, isInline: true, styles: [":host{display:contents}.modal-overlay{align-items:center;background-color:var(--ls-modal-backdrop-bg);display:flex;inset:0;justify-content:center;padding:1rem;position:fixed;z-index:var(--ls-modal-z-index)}.modal-overlay-body{align-items:flex-start;overflow-y:auto}.modal-panel{background-color:var(--ls-color-white);border-radius:var(--ls-border-radius-lg);box-shadow:0 20px 60px #0000004d;display:flex;flex-direction:column;max-height:calc(100vh - 2rem);outline:none;position:relative;width:100%}.modal-max-sm{max-width:24rem}.modal-max-md{max-width:32rem}.modal-max-lg{max-width:48rem}.modal-max-xl{max-width:64rem}.modal-max-full{max-width:100%}.modal-full-screen{border-radius:0;height:100vh;max-height:100vh;max-width:100vw;width:100vw}.modal-full-width{max-width:100%}.modal-scroll-dialog{max-height:calc(100vh - 2rem);overflow:hidden}.modal-scroll-body{max-height:none}.modal-close-btn{align-items:center;background:transparent;border:none;border-radius:.25rem;color:inherit;cursor:pointer;display:flex;justify-content:center;padding:.25rem;position:absolute;right:.75rem;top:.75rem;transition:background-color .15s}.modal-close-btn:hover{background-color:var(--ls-color-dark-light)}.modal-has-close-btn .modal-title{padding-right:3rem}.modal-title{border-bottom:1px solid var(--ls-color-dark-light);font-family:var(--ls-font-family);font-size:1.125rem;font-weight:700;padding:1.25rem 1.5rem}.modal-content{flex:1;overflow-y:auto;padding:1.5rem}.modal-actions{border-top:1px solid var(--ls-color-dark-light);display:flex;gap:.75rem;justify-content:flex-end;padding:1rem 1.5rem}body.dark .modal-panel{background-color:#1b2e4b;box-shadow:0 20px 60px #0009}body.dark .modal-title{border-bottom-color:#253958}body.dark .modal-actions{border-top-color:#253958}body.dark .modal-close-btn:hover{background-color:#253958}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
661
+ }
662
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ModalComponent, decorators: [{
663
+ type: Component,
664
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, imports: [], selector: 'ls-modal', standalone: true, template: `
665
+ @if (open()) {
666
+ <div [class]="overlayClasses()" (click)="onBackdropClick()">
667
+ <div
668
+ #panel
669
+ [attr.aria-labelledby]="labelledById()"
670
+ [attr.aria-modal]="true"
671
+ [class]="panelClasses()"
672
+ role="dialog"
673
+ tabindex="-1"
674
+ (click)="$event.stopPropagation()">
675
+ @if (showCloseButton()) {
676
+ <button
677
+ aria-label="Close"
678
+ class="modal-close-btn"
679
+ type="button"
680
+ (click)="onCloseButtonClick()">
681
+ <i class="ls-icon ls-x ls-icon-sm"></i>
682
+ </button>
683
+ }
684
+ <ng-content />
685
+ </div>
686
+ </div>
687
+ }
688
+ `, styles: [":host{display:contents}.modal-overlay{align-items:center;background-color:var(--ls-modal-backdrop-bg);display:flex;inset:0;justify-content:center;padding:1rem;position:fixed;z-index:var(--ls-modal-z-index)}.modal-overlay-body{align-items:flex-start;overflow-y:auto}.modal-panel{background-color:var(--ls-color-white);border-radius:var(--ls-border-radius-lg);box-shadow:0 20px 60px #0000004d;display:flex;flex-direction:column;max-height:calc(100vh - 2rem);outline:none;position:relative;width:100%}.modal-max-sm{max-width:24rem}.modal-max-md{max-width:32rem}.modal-max-lg{max-width:48rem}.modal-max-xl{max-width:64rem}.modal-max-full{max-width:100%}.modal-full-screen{border-radius:0;height:100vh;max-height:100vh;max-width:100vw;width:100vw}.modal-full-width{max-width:100%}.modal-scroll-dialog{max-height:calc(100vh - 2rem);overflow:hidden}.modal-scroll-body{max-height:none}.modal-close-btn{align-items:center;background:transparent;border:none;border-radius:.25rem;color:inherit;cursor:pointer;display:flex;justify-content:center;padding:.25rem;position:absolute;right:.75rem;top:.75rem;transition:background-color .15s}.modal-close-btn:hover{background-color:var(--ls-color-dark-light)}.modal-has-close-btn .modal-title{padding-right:3rem}.modal-title{border-bottom:1px solid var(--ls-color-dark-light);font-family:var(--ls-font-family);font-size:1.125rem;font-weight:700;padding:1.25rem 1.5rem}.modal-content{flex:1;overflow-y:auto;padding:1.5rem}.modal-actions{border-top:1px solid var(--ls-color-dark-light);display:flex;gap:.75rem;justify-content:flex-end;padding:1rem 1.5rem}body.dark .modal-panel{background-color:#1b2e4b;box-shadow:0 20px 60px #0009}body.dark .modal-title{border-bottom-color:#253958}body.dark .modal-actions{border-top-color:#253958}body.dark .modal-close-btn:hover{background-color:#253958}\n"] }]
689
+ }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], disableBackdropClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableBackdropClose", required: false }] }], fullScreen: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullScreen", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], scroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "scroll", required: false }] }], showCloseButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCloseButton", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }], _titleComponent: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ModalTitleComponent), { isSignal: true }] }], _panel: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }], onEscape: [{
690
+ type: HostListener,
691
+ args: ['document:keydown.escape']
692
+ }] } });
693
+
694
+ class ModalContentComponent {
695
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ModalContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
696
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: ModalContentComponent, isStandalone: true, selector: "ls-modal-content", host: { classAttribute: "modal-content" }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
697
+ }
698
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ModalContentComponent, decorators: [{
699
+ type: Component,
700
+ args: [{
701
+ changeDetection: ChangeDetectionStrategy.OnPush,
702
+ host: { class: 'modal-content' },
703
+ imports: [],
704
+ selector: 'ls-modal-content',
705
+ standalone: true,
706
+ template: `<ng-content />`,
707
+ }]
708
+ }] });
709
+
710
+ class PopoverComponent {
711
+ constructor() {
712
+ this._renderer = inject(Renderer2);
713
+ this._destroyRef = inject(DestroyRef);
714
+ this._document = inject(DOCUMENT);
715
+ this._elementRef = inject(ElementRef);
716
+ this._cleanupScroll = null;
717
+ this.placement = input('bottom', ...(ngDevMode ? [{ debugName: "placement" }] : []));
718
+ this.showArrow = input(true, ...(ngDevMode ? [{ debugName: "showArrow" }] : []));
719
+ this.offset = input(8, ...(ngDevMode ? [{ debugName: "offset" }] : []));
720
+ this.autoFlip = input(true, ...(ngDevMode ? [{ debugName: "autoFlip" }] : []));
721
+ this.trigger = input(undefined, ...(ngDevMode ? [{ debugName: "trigger" }] : []));
722
+ this.isOpen = model(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
723
+ this.onOpened = output();
724
+ this.onHidden = output();
725
+ this._panelRef = viewChild('panelRef', ...(ngDevMode ? [{ debugName: "_panelRef" }] : []));
726
+ this._currentPlacement = signal('bottom', ...(ngDevMode ? [{ debugName: "_currentPlacement" }] : []));
727
+ this._isAnimating = signal(false, ...(ngDevMode ? [{ debugName: "_isAnimating" }] : []));
728
+ this._cleanupClickOutside = null;
729
+ this._cleanupEscape = null;
730
+ this._hoverBridgeTimeout = null;
731
+ this._wasOpen = false;
732
+ this._panelClasses = computed(() => ['popover-panel', `popover-${this._currentPlacement()}`].join(' '), ...(ngDevMode ? [{ debugName: "_panelClasses" }] : []));
733
+ this._arrowClasses = computed(() => `popover-arrow popover-arrow-${this._currentPlacement()}`, ...(ngDevMode ? [{ debugName: "_arrowClasses" }] : []));
734
+ effect(() => {
735
+ const isOpen = this.isOpen();
736
+ untracked(() => {
737
+ if (isOpen) {
738
+ this._currentPlacement.set(this.placement());
739
+ this._isAnimating.set(true);
740
+ this._setupListeners();
741
+ setTimeout(() => {
742
+ if (this.isOpen()) {
743
+ this._computePosition();
744
+ }
745
+ }, 0);
746
+ this._wasOpen = true;
747
+ }
748
+ else if (this._wasOpen) {
749
+ this._isAnimating.set(true);
750
+ this._wasOpen = false;
751
+ }
752
+ else {
753
+ this._removeListeners();
754
+ }
755
+ });
756
+ });
757
+ this._destroyRef.onDestroy(() => {
758
+ this._removeListeners();
759
+ if (this._hoverBridgeTimeout) {
760
+ clearTimeout(this._hoverBridgeTimeout);
761
+ }
762
+ });
763
+ }
764
+ open() {
765
+ this.isOpen.set(true);
766
+ }
767
+ close() {
768
+ this.isOpen.set(false);
769
+ }
770
+ toggle() {
771
+ if (this.isOpen()) {
772
+ this.close();
773
+ }
774
+ else {
775
+ this.open();
776
+ }
777
+ }
778
+ _onAnimationEnd() {
779
+ this._isAnimating.set(false);
780
+ if (this.isOpen()) {
781
+ this.onOpened.emit();
782
+ }
783
+ else {
784
+ this._removeListeners();
785
+ this.onHidden.emit();
786
+ }
787
+ }
788
+ _onPanelMouseEnter() {
789
+ if (this._hoverBridgeTimeout) {
790
+ clearTimeout(this._hoverBridgeTimeout);
791
+ this._hoverBridgeTimeout = null;
792
+ }
793
+ }
794
+ _onPanelMouseLeave() {
795
+ this._hoverBridgeTimeout = setTimeout(() => this.close(), 100);
796
+ }
797
+ _computePosition() {
798
+ const anchor = this.trigger() ??
799
+ this._elementRef.nativeElement.parentElement;
800
+ const panel = this._panelRef()?.nativeElement;
801
+ if (!anchor || !panel)
802
+ return;
803
+ const anchorRect = anchor.getBoundingClientRect();
804
+ const panelRect = panel.getBoundingClientRect();
805
+ const offset = this.offset();
806
+ let placement = this._currentPlacement();
807
+ if (this.autoFlip()) {
808
+ placement = this._getFlippedPlacement(placement, anchorRect, panelRect, offset);
809
+ this._currentPlacement.set(placement);
810
+ }
811
+ let top = 0;
812
+ let left = 0;
813
+ switch (placement) {
814
+ case 'top':
815
+ top = anchorRect.top - panelRect.height - offset;
816
+ left =
817
+ anchorRect.left +
818
+ (anchorRect.width - panelRect.width) / 2;
819
+ break;
820
+ case 'bottom':
821
+ top = anchorRect.bottom + offset;
822
+ left =
823
+ anchorRect.left +
824
+ (anchorRect.width - panelRect.width) / 2;
825
+ break;
826
+ case 'left':
827
+ top =
828
+ anchorRect.top +
829
+ (anchorRect.height - panelRect.height) / 2;
830
+ left = anchorRect.left - panelRect.width - offset;
831
+ break;
832
+ case 'right':
833
+ top =
834
+ anchorRect.top +
835
+ (anchorRect.height - panelRect.height) / 2;
836
+ left = anchorRect.right + offset;
837
+ break;
838
+ }
839
+ panel.style.setProperty('--popover-top', `${top}px`);
840
+ panel.style.setProperty('--popover-left', `${left}px`);
841
+ }
842
+ _getFlippedPlacement(placement, anchorRect, panelRect, offset) {
843
+ const viewportWidth = this._document.defaultView?.innerWidth ?? 0;
844
+ const viewportHeight = this._document.defaultView?.innerHeight ?? 0;
845
+ const opposites = {
846
+ top: 'bottom',
847
+ bottom: 'top',
848
+ left: 'right',
849
+ right: 'left',
850
+ };
851
+ switch (placement) {
852
+ case 'top':
853
+ if (anchorRect.top - panelRect.height - offset < 0) {
854
+ return opposites[placement];
855
+ }
856
+ break;
857
+ case 'bottom':
858
+ if (anchorRect.bottom + panelRect.height + offset >
859
+ viewportHeight) {
860
+ return opposites[placement];
861
+ }
862
+ break;
863
+ case 'left':
864
+ if (anchorRect.left - panelRect.width - offset < 0) {
865
+ return opposites[placement];
866
+ }
867
+ break;
868
+ case 'right':
869
+ if (anchorRect.right + panelRect.width + offset >
870
+ viewportWidth) {
871
+ return opposites[placement];
872
+ }
873
+ break;
874
+ }
875
+ return placement;
876
+ }
877
+ _setupListeners() {
878
+ this._removeListeners();
879
+ this._cleanupClickOutside = this._renderer.listen(this._document, 'click', (event) => {
880
+ const anchor = this.trigger() ??
881
+ this._elementRef.nativeElement.parentElement;
882
+ const panel = this._panelRef()?.nativeElement;
883
+ const target = event.target;
884
+ if (panel &&
885
+ !panel.contains(target) &&
886
+ anchor &&
887
+ !anchor.contains(target)) {
888
+ this.close();
889
+ }
890
+ });
891
+ this._cleanupEscape = this._renderer.listen(this._document, 'keydown', (event) => {
892
+ if (event.key === 'Escape') {
893
+ this.close();
894
+ }
895
+ });
896
+ this._cleanupScroll = this._renderer.listen('window', 'scroll', () => {
897
+ if (this.isOpen()) {
898
+ this.close();
899
+ }
900
+ }, { capture: true });
901
+ }
902
+ _removeListeners() {
903
+ if (this._cleanupClickOutside) {
904
+ this._cleanupClickOutside();
905
+ this._cleanupClickOutside = null;
906
+ }
907
+ if (this._cleanupEscape) {
908
+ this._cleanupEscape();
909
+ this._cleanupEscape = null;
910
+ }
911
+ if (this._cleanupScroll) {
912
+ this._cleanupScroll();
913
+ this._cleanupScroll = null;
914
+ }
915
+ }
916
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: PopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
917
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: PopoverComponent, isStandalone: true, selector: "ls-popover", inputs: { placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, showArrow: { classPropertyName: "showArrow", publicName: "showArrow", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, autoFlip: { classPropertyName: "autoFlip", publicName: "autoFlip", isSignal: true, isRequired: false, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isOpen: "isOpenChange", onOpened: "onOpened", onHidden: "onHidden" }, viewQueries: [{ propertyName: "_panelRef", first: true, predicate: ["panelRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
918
+ @if (isOpen() || _isAnimating()) {
919
+ <div
920
+ [class]="_panelClasses()"
921
+ [class.popover-enter]="isOpen() && _isAnimating()"
922
+ [class.popover-exit]="!isOpen() && _isAnimating()"
923
+ (animationend)="_onAnimationEnd()"
924
+ (mouseenter)="_onPanelMouseEnter()"
925
+ (mouseleave)="_onPanelMouseLeave()"
926
+ role="dialog"
927
+ aria-modal="false"
928
+ #panelRef>
929
+ @if (showArrow()) {
930
+ <span [class]="_arrowClasses()"></span>
931
+ }
932
+ <ng-content />
933
+ </div>
934
+ }
935
+ `, isInline: true, styles: [":host{display:contents}.popover-panel{position:fixed;top:var(--popover-top, 0);left:var(--popover-left, 0);z-index:1050;background:var(--ls-color-white, #fff);border:1px solid var(--ls-color-border, #e0e6ed);border-radius:8px;box-shadow:0 4px 16px #0000001f;padding:12px 16px;animation-duration:.15s;animation-fill-mode:both;animation-timing-function:ease-out}.popover-enter{animation-name:popoverFadeIn}.popover-exit{animation-name:popoverFadeOut}@keyframes popoverFadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}@keyframes popoverFadeOut{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(4px)}}.popover-arrow{position:absolute;width:10px;height:10px;background:inherit;border:inherit;transform:rotate(45deg);z-index:-1}.popover-arrow-top{bottom:-6px;left:50%;margin-left:-5px;border-top:0;border-left:0}.popover-arrow-bottom{top:-6px;left:50%;margin-left:-5px;border-bottom:0;border-right:0}.popover-arrow-left{right:-6px;top:50%;margin-top:-5px;border-bottom:0;border-left:0}.popover-arrow-right{left:-6px;top:50%;margin-top:-5px;border-top:0;border-right:0}:host-context(body.dark) .popover-panel{background:#1b2e4b!important;border-color:#253b5c!important;color:#e0e6ed!important;box-shadow:0 4px 16px #00000080!important}:host-context(.dark) .popover-panel{background:#1b2e4b!important;border-color:#253b5c!important;color:#e0e6ed!important}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
936
+ }
937
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: PopoverComponent, decorators: [{
938
+ type: Component,
939
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ls-popover', standalone: true, template: `
940
+ @if (isOpen() || _isAnimating()) {
941
+ <div
942
+ [class]="_panelClasses()"
943
+ [class.popover-enter]="isOpen() && _isAnimating()"
944
+ [class.popover-exit]="!isOpen() && _isAnimating()"
945
+ (animationend)="_onAnimationEnd()"
946
+ (mouseenter)="_onPanelMouseEnter()"
947
+ (mouseleave)="_onPanelMouseLeave()"
948
+ role="dialog"
949
+ aria-modal="false"
950
+ #panelRef>
951
+ @if (showArrow()) {
952
+ <span [class]="_arrowClasses()"></span>
953
+ }
954
+ <ng-content />
955
+ </div>
956
+ }
957
+ `, styles: [":host{display:contents}.popover-panel{position:fixed;top:var(--popover-top, 0);left:var(--popover-left, 0);z-index:1050;background:var(--ls-color-white, #fff);border:1px solid var(--ls-color-border, #e0e6ed);border-radius:8px;box-shadow:0 4px 16px #0000001f;padding:12px 16px;animation-duration:.15s;animation-fill-mode:both;animation-timing-function:ease-out}.popover-enter{animation-name:popoverFadeIn}.popover-exit{animation-name:popoverFadeOut}@keyframes popoverFadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}@keyframes popoverFadeOut{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(4px)}}.popover-arrow{position:absolute;width:10px;height:10px;background:inherit;border:inherit;transform:rotate(45deg);z-index:-1}.popover-arrow-top{bottom:-6px;left:50%;margin-left:-5px;border-top:0;border-left:0}.popover-arrow-bottom{top:-6px;left:50%;margin-left:-5px;border-bottom:0;border-right:0}.popover-arrow-left{right:-6px;top:50%;margin-top:-5px;border-bottom:0;border-left:0}.popover-arrow-right{left:-6px;top:50%;margin-top:-5px;border-top:0;border-right:0}:host-context(body.dark) .popover-panel{background:#1b2e4b!important;border-color:#253b5c!important;color:#e0e6ed!important;box-shadow:0 4px 16px #00000080!important}:host-context(.dark) .popover-panel{background:#1b2e4b!important;border-color:#253b5c!important;color:#e0e6ed!important}\n"] }]
958
+ }], ctorParameters: () => [], propDecorators: { placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], showArrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "showArrow", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], autoFlip: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFlip", required: false }] }], trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }, { type: i0.Output, args: ["isOpenChange"] }], onOpened: [{ type: i0.Output, args: ["onOpened"] }], onHidden: [{ type: i0.Output, args: ["onHidden"] }], _panelRef: [{ type: i0.ViewChild, args: ['panelRef', { isSignal: true }] }] } });
959
+
960
+ let nextId = 0;
961
+ class TooltipComponent {
962
+ constructor() {
963
+ this.content = input.required(...(ngDevMode ? [{ debugName: "content" }] : []));
964
+ this.placement = input('top', ...(ngDevMode ? [{ debugName: "placement" }] : []));
965
+ this.backgroundClass = input('dark', ...(ngDevMode ? [{ debugName: "backgroundClass" }] : []));
966
+ this.disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
967
+ this._isVisible = signal(false, ...(ngDevMode ? [{ debugName: "_isVisible" }] : []));
968
+ this._tooltipId = `ls-tooltip-${nextId++}`;
969
+ }
970
+ get tooltipClasses() {
971
+ return [
972
+ 'tooltip-box',
973
+ `tooltip-${this.placement()}`,
974
+ `tooltip-bg-${this.backgroundClass()}`,
975
+ ].join(' ');
976
+ }
977
+ show() {
978
+ this._isVisible.set(true);
979
+ }
980
+ hide() {
981
+ this._isVisible.set(false);
982
+ }
983
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: TooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
984
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: TooltipComponent, isStandalone: true, selector: "ls-tooltip", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: true, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, backgroundClass: { classPropertyName: "backgroundClass", publicName: "backgroundClass", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
985
+ <span
986
+ class="ls-tooltip-trigger"
987
+ [class.ls-tooltip-disabled]="disabled()"
988
+ [attr.aria-describedby]="disabled() ? null : _tooltipId"
989
+ (mouseenter)="show()"
990
+ (mouseleave)="hide()"
991
+ (focus)="show()"
992
+ (blur)="hide()">
993
+ <ng-content />
994
+ @if (_isVisible() && !disabled()) {
995
+ <span
996
+ [id]="_tooltipId"
997
+ role="tooltip"
998
+ [attr.aria-hidden]="!_isVisible()"
999
+ [class]="tooltipClasses">
1000
+ {{ content() }}
1001
+ <span class="tooltip-arrow"></span>
1002
+ </span>
1003
+ }
1004
+ </span>
1005
+ `, isInline: true, styles: [":host{display:contents}.ls-tooltip-trigger{position:relative;display:inline-flex}.ls-tooltip-disabled{pointer-events:none}.tooltip-box{position:absolute;z-index:10;padding:2px 8px;border-radius:6px;font-family:var(--ls-font-family);font-size:.8rem;font-weight:500;white-space:nowrap;box-shadow:0 2px 8px #00000026;pointer-events:none;animation:tooltip-fade-in var(--ls-transition-duration) ease forwards}@keyframes tooltip-fade-in{0%{opacity:0}to{opacity:1}}.tooltip-top{bottom:calc(100% + 8px);left:50%;transform:translate(-50%)}.tooltip-bottom{top:calc(100% + 8px);left:50%;transform:translate(-50%)}.tooltip-left{right:calc(100% + 8px);top:50%;transform:translateY(-50%)}.tooltip-right{left:calc(100% + 8px);top:50%;transform:translateY(-50%)}.tooltip-arrow{position:absolute;width:0;height:0;border:6px solid transparent}.tooltip-top .tooltip-arrow{bottom:-6px;left:50%;transform:translate(-50%);border-bottom:none;border-top-color:inherit}.tooltip-bottom .tooltip-arrow{top:-6px;left:50%;transform:translate(-50%);border-top:none;border-bottom-color:inherit}.tooltip-left .tooltip-arrow{right:-6px;top:50%;transform:translateY(-50%);border-right:none;border-left-color:inherit}.tooltip-right .tooltip-arrow{left:-6px;top:50%;transform:translateY(-50%);border-left:none;border-right-color:inherit}.tooltip-bg-primary{background-color:var(--ls-color-primary);color:#fff;border-color:var(--ls-color-primary)}.tooltip-bg-success{background-color:var(--ls-color-success);color:#fff;border-color:var(--ls-color-success)}.tooltip-bg-info{background-color:var(--ls-color-info);color:#fff;border-color:var(--ls-color-info)}.tooltip-bg-danger{background-color:var(--ls-color-danger);color:#fff;border-color:var(--ls-color-danger)}.tooltip-bg-warning{background-color:var(--ls-color-warning);color:#fff;border-color:var(--ls-color-warning)}.tooltip-bg-secondary{background-color:var(--ls-color-secondary);color:#fff;border-color:var(--ls-color-secondary)}.tooltip-bg-dark{background-color:var(--ls-color-dark);color:#fff;border-color:var(--ls-color-dark)}body.dark .tooltip-bg-dark{background-color:#e0e6ed;color:var(--ls-color-dark);border-color:#e0e6ed}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1006
+ }
1007
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: TooltipComponent, decorators: [{
1008
+ type: Component,
1009
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ls-tooltip', standalone: true, template: `
1010
+ <span
1011
+ class="ls-tooltip-trigger"
1012
+ [class.ls-tooltip-disabled]="disabled()"
1013
+ [attr.aria-describedby]="disabled() ? null : _tooltipId"
1014
+ (mouseenter)="show()"
1015
+ (mouseleave)="hide()"
1016
+ (focus)="show()"
1017
+ (blur)="hide()">
1018
+ <ng-content />
1019
+ @if (_isVisible() && !disabled()) {
1020
+ <span
1021
+ [id]="_tooltipId"
1022
+ role="tooltip"
1023
+ [attr.aria-hidden]="!_isVisible()"
1024
+ [class]="tooltipClasses">
1025
+ {{ content() }}
1026
+ <span class="tooltip-arrow"></span>
1027
+ </span>
1028
+ }
1029
+ </span>
1030
+ `, styles: [":host{display:contents}.ls-tooltip-trigger{position:relative;display:inline-flex}.ls-tooltip-disabled{pointer-events:none}.tooltip-box{position:absolute;z-index:10;padding:2px 8px;border-radius:6px;font-family:var(--ls-font-family);font-size:.8rem;font-weight:500;white-space:nowrap;box-shadow:0 2px 8px #00000026;pointer-events:none;animation:tooltip-fade-in var(--ls-transition-duration) ease forwards}@keyframes tooltip-fade-in{0%{opacity:0}to{opacity:1}}.tooltip-top{bottom:calc(100% + 8px);left:50%;transform:translate(-50%)}.tooltip-bottom{top:calc(100% + 8px);left:50%;transform:translate(-50%)}.tooltip-left{right:calc(100% + 8px);top:50%;transform:translateY(-50%)}.tooltip-right{left:calc(100% + 8px);top:50%;transform:translateY(-50%)}.tooltip-arrow{position:absolute;width:0;height:0;border:6px solid transparent}.tooltip-top .tooltip-arrow{bottom:-6px;left:50%;transform:translate(-50%);border-bottom:none;border-top-color:inherit}.tooltip-bottom .tooltip-arrow{top:-6px;left:50%;transform:translate(-50%);border-top:none;border-bottom-color:inherit}.tooltip-left .tooltip-arrow{right:-6px;top:50%;transform:translateY(-50%);border-right:none;border-left-color:inherit}.tooltip-right .tooltip-arrow{left:-6px;top:50%;transform:translateY(-50%);border-left:none;border-right-color:inherit}.tooltip-bg-primary{background-color:var(--ls-color-primary);color:#fff;border-color:var(--ls-color-primary)}.tooltip-bg-success{background-color:var(--ls-color-success);color:#fff;border-color:var(--ls-color-success)}.tooltip-bg-info{background-color:var(--ls-color-info);color:#fff;border-color:var(--ls-color-info)}.tooltip-bg-danger{background-color:var(--ls-color-danger);color:#fff;border-color:var(--ls-color-danger)}.tooltip-bg-warning{background-color:var(--ls-color-warning);color:#fff;border-color:var(--ls-color-warning)}.tooltip-bg-secondary{background-color:var(--ls-color-secondary);color:#fff;border-color:var(--ls-color-secondary)}.tooltip-bg-dark{background-color:var(--ls-color-dark);color:#fff;border-color:var(--ls-color-dark)}body.dark .tooltip-bg-dark{background-color:#e0e6ed;color:var(--ls-color-dark);border-color:#e0e6ed}\n"] }]
1031
+ }], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: true }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], backgroundClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "backgroundClass", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
1032
+
1033
+ /**
1034
+ * Generated bundle index. Do not edit.
1035
+ */
1036
+
1037
+ export { MenuComponent, MenuItemComponent, MenuTriggerDirective, ModalActionsComponent, ModalComponent, ModalContentComponent, ModalStackService, ModalTitleComponent, PopoverComponent, TooltipComponent };
1038
+ //# sourceMappingURL=lumston-ds-angular-src-overlay.mjs.map