ng-hub-ui-buttons 22.11.0 → 22.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -55,7 +55,7 @@ This library is part of the **ng-hub-ui** ecosystem:
55
55
  - **Four sizes** — `sm`, `md`, `lg`, `xl` with proportional padding and font scaling.
56
56
  - **FAB with nine positions** — fixed-viewport placement at any corner, edge-center or screen-center via CSS logical properties (RTL-ready).
57
57
  - **Speed Dial** — expandable FAB menu with `isOpen` two-way model, directional expansion and Escape close.
58
- - **Overlay Dropdown** — attaches any `<ng-template>` to any trigger; eight placement options, click or hover trigger, backdrop and scroll close, no CDK dependency.
58
+ - **Overlay Dropdown** — attaches any `<ng-template>` to any trigger; eight placement options, click or hover trigger, click-outside and scroll close, no CDK dependency.
59
59
  - **Cross-library row actions** — `hubActionsAdapter` draws another library's row buttons and menus with these components, with no dependency in either direction.
60
60
  - **Extensible SCSS token system** — `:where()` zero-specificity defaults mean any consumer rule wins without `!important`. Public mixin API lets you register custom semantic colors.
61
61
 
@@ -160,21 +160,35 @@ hub-button, [hubButton] {
160
160
  | `position` | `top-start \| top-center \| top-end \| middle-start \| center \| middle-end \| bottom-start \| bottom-center \| bottom-end` | `bottom-end` | Fixed viewport position |
161
161
  | `size` | `mini \| standard \| large` | `standard` | Button size |
162
162
  | `color` | semantic | `primary` | Colour variant |
163
- | `collapseOnScroll` | `boolean` | `false` | Hides extended label on scroll, expands on stop |
163
+ | `extended` | `boolean` | `false` | Renders the pill variant with a projected label beside the icon |
164
+ | `collapseOnScroll` | `boolean` | `false` | Collapses an extended FAB to icon-only while the page is scrolled past 50px, and expands it again near the top |
164
165
  | `disabled` | `boolean` | `false` | Disables the button |
165
166
 
166
167
  Output: `fabClick`.
167
168
 
169
+ Content slots: `[slot=icon]` always renders, `[slot=label]` only in the extended form. A FAB that is not extended projects its default content instead of the label.
170
+
171
+ ```html
172
+ <hub-fab extended aria-label="New document">
173
+ <i slot="icon" class="fa-solid fa-plus"></i>
174
+ <span slot="label">New document</span>
175
+ </hub-fab>
176
+ ```
177
+
178
+ > The host element *is* the control, so it advertises `role="button"`, a focusable `tabindex` and Enter/Space activation. Don't nest it inside another interactive element, and give it an `aria-label` when it only holds an icon.
179
+
168
180
  ### `HubSpeedDialComponent` — `<hub-speed-dial>`
169
181
 
170
182
  | Input / Output | Type | Default | Description |
171
183
  |---|---|---|---|
172
184
  | `isOpen` | `model(false)` | `false` | Two-way binding for open/closed state |
173
185
  | `position` | same as FAB | `bottom-end` | Fixed viewport position |
186
+ | `size` | `mini \| standard \| large` | `standard` | Trigger button size |
174
187
  | `color` | semantic | `primary` | Trigger button colour |
175
188
  | `direction` | `up \| down \| left \| right` | `up` | Direction in which action items expand |
189
+ | `trigger` | `click \| hover` | `click` | Interaction that opens the dial |
176
190
 
177
- Methods: `open()`, `close()`, `toggle()`. Closes on Escape.
191
+ Outputs: `opened`, `closed`, plus `isOpenChange` from the two-way `isOpen` model. Methods: `open()`, `close()`, `toggle()`. Closes on Escape.
178
192
 
179
193
  Use `hubTrigger` on the element projected as the trigger button:
180
194
 
@@ -192,7 +206,7 @@ Use `hubTrigger` on the element projected as the trigger button:
192
206
  |-------|------|---------|-------------|
193
207
  | `icon` | `string` | — | CSS class(es) applied to an `<i>` element (e.g. `fa-solid fa-pen`) |
194
208
  | `label` | `string` | — | Tooltip label shown beside the item |
195
- | `color` | semantic | `primary` | Item button colour |
209
+ | `color` | semantic \| `default` | `default` | Item button colour; `default` keeps the neutral appearance |
196
210
  | `disabled` | `boolean` | `false` | Disables the item |
197
211
 
198
212
  Output: `itemClick`.
@@ -210,7 +224,7 @@ Output: `itemClick`.
210
224
  | `panelClass` | `string` | `''` | Extra CSS class added to the overlay panel |
211
225
  | `isOpen` | `model(false)` | — | Two-way open state |
212
226
 
213
- Outputs: `opened`, `closed`. Methods: `open()`, `close()`, `toggle()`. Closes on Escape, backdrop click and scroll. Only one dropdown is open at a time: opening any closes whichever was already open, however it was opened.
227
+ Outputs: `opened`, `closed`. Methods: `open()`, `close()`, `toggle()`. Closes on Escape, a click outside and scroll. Only one dropdown is open at a time: opening any closes whichever was already open, however it was opened.
214
228
 
215
229
  ### `HubDropdownPanelComponent` — `<hub-dropdown-panel>`
216
230
 
@@ -269,18 +283,18 @@ All visual properties are CSS custom properties scoped with `:where()` (zero spe
269
283
 
270
284
  ```css
271
285
  /* Button */
272
- --hub-button-padding-x: 0.875rem;
273
- --hub-button-padding-y: 0.4375rem;
286
+ --hub-button-padding-x: var(--hub-ref-space-3, 1rem);
287
+ --hub-button-padding-y: var(--hub-ref-space-2, 0.5rem);
274
288
  --hub-button-border-radius: var(--hub-sys-radius-md, 0.375rem);
275
289
  --hub-button-border-width: 1.5px;
276
- --hub-button-font-size: 1rem;
277
- --hub-button-font-weight: 500;
278
- --hub-button-gap: 0.375rem;
279
- --hub-button-transition: all 0.15s ease;
290
+ --hub-button-font-size: var(--hub-ref-font-size-base, 1rem);
291
+ --hub-button-font-weight: var(--hub-ref-font-weight-medium, 500);
292
+ --hub-button-gap: var(--hub-ref-space-2, 0.5rem);
293
+ --hub-button-transition: var(--hub-sys-transition-fast, all 0.15s ease-in-out);
280
294
  --hub-button-spinner-size: 0.875em;
281
295
  --hub-button-spinner-duration: 0.7s;
282
296
  --hub-button-spinner: url("data:image/svg+xml,…"); /* the loading glyph — swap for any SVG */
283
- --hub-button-disabled-opacity: 0.55;
297
+ --hub-button-disabled-opacity: var(--hub-sys-opacity-disabled, 0.65);
284
298
 
285
299
  /* Button interaction slots (overridable hover / pressed families) */
286
300
  --hub-btn-hover-bg: var(--hub-btn-accent-subtle);
@@ -295,15 +309,18 @@ All visual properties are CSS custom properties scoped with `:where()` (zero spe
295
309
  --hub-fab-size-standard: 3.5rem;
296
310
  --hub-fab-size-large: 4.5rem;
297
311
  --hub-fab-border-radius: 50%;
298
- --hub-fab-shadow: var(--hub-sys-shadow-md);
299
- --hub-fab-shadow-hover: var(--hub-sys-shadow-lg);
300
- --hub-fab-offset: 1rem;
301
- --hub-fab-zindex: 1030;
312
+ --hub-fab-shadow: var(--hub-sys-shadow-md, 0 0.5rem 1rem rgba(0, 0, 0, 0.15));
313
+ --hub-fab-shadow-hover: var(--hub-sys-shadow-lg, 0 1rem 3rem rgba(0, 0, 0, 0.175));
314
+ --hub-fab-offset: var(--hub-ref-space-3, 1rem);
315
+ --hub-fab-zindex: var(--hub-sys-zindex-fixed, 1030);
302
316
  --hub-fab-transition: box-shadow 0.2s ease, transform 0.15s ease;
317
+ --hub-fab-extended-height: 3.5rem;
318
+ --hub-fab-extended-radius: 1.75rem;
319
+ --hub-fab-extended-padding-x: 1.25rem;
303
320
 
304
321
  /* Speed Dial */
305
322
  --hub-speed-dial-gap: 0.625rem;
306
- --hub-speed-dial-zindex: 1030;
323
+ --hub-speed-dial-zindex: var(--hub-sys-zindex-fixed, 1030);
307
324
  --hub-speed-dial-animation: 0.2s ease;
308
325
 
309
326
  /* Dropdown panel */
@@ -402,6 +419,7 @@ hub-button, [hubButton] {
402
419
  |---|---|---|
403
420
  | `hub-btn-variant-rules($bg, $color, $border, $hover-*, $active-*, …)` | inside a `hub-button, [hubButton]` variant selector | Generic primitive — every appearance property as a **named** param (no positional `$type`) |
404
421
  | `hub-btn-color-rules($type)` | global `hub-button, [hubButton]` block | Registers one custom accent (`--hub-btn-accent` → `--hub-sys-color-$type`); all five appearances derive from it |
422
+ | `hub-btn-theme($accent, $border-radius, $padding-x, $padding-y, $font-size)` | any selector holding buttons | One-call token theming — every parameter optional, only the ones you pass are emitted |
405
423
  | `hub-fab-color($type)` | root | Global `.hub-fab-{type}` color rule |
406
424
  | `hub-dropdown-panel-color($type)` | root | Global color rule for `hub-dropdown-panel` |
407
425
  | `hub-dropdown-panel-color-rules($type)` | inside `hub-dropdown-panel` selector | CSS properties only — bring your own selector |
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { InjectionToken, inject, ElementRef, input, booleanAttribute, ChangeDetectionStrategy, Component, output, signal, DestroyRef, ViewEncapsulation, model, PLATFORM_ID, ViewContainerRef, Directive } from '@angular/core';
3
3
  import { resolveHubAccent, OverlayService } from 'ng-hub-ui-utils';
4
4
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
5
- import { fromEvent } from 'rxjs';
5
+ import { fromEvent, Subscription } from 'rxjs';
6
6
  import { debounceTime, filter, take } from 'rxjs/operators';
7
7
  import { isPlatformBrowser, DOCUMENT, NgClass } from '@angular/common';
8
8
 
@@ -180,22 +180,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
180
180
  * Supports circular and extended (pill with label) variants.
181
181
  * When collapseOnScroll is true, an extended FAB collapses to icon-only after 50px scroll.
182
182
  * Uses inset-inline-* / inset-block-* CSS logical properties for RTL support.
183
+ *
184
+ * The host element *is* the control — a component cannot swap its own tag for a native
185
+ * `<button>` — so it self-advertises `role="button"`, a focusable `tabindex` and
186
+ * Enter/Space activation to stay reachable without a pointer.
187
+ *
188
+ * **Accessibility caveat:** because it reports `role="button"`, a `<hub-fab>` must not be
189
+ * nested inside another interactive element, which would produce an invalid
190
+ * nested-interactive tree. Give it an accessible name (`aria-label`) when the projected
191
+ * content is only an icon.
183
192
  */
184
193
  class HubFabComponent {
185
194
  color = input('primary', /* @ts-ignore */
186
195
  ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
187
196
  size = input('standard', /* @ts-ignore */
188
197
  ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
189
- extended = input(false, /* @ts-ignore */
190
- ...(ngDevMode ? [{ debugName: "extended" }] : /* istanbul ignore next */ []));
198
+ /**
199
+ * Renders the pill variant with a projected label.
200
+ *
201
+ * Transformed, so the bare HTML form works: `<hub-fab extended>` passes the empty
202
+ * string an attribute without a value carries, which an untransformed `input(false)`
203
+ * rejects at compile time.
204
+ */
205
+ extended = input(false, { ...(ngDevMode ? { debugName: "extended" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
191
206
  /** Fixed viewport position. 9-slot grid including center. */
192
207
  position = input('bottom-end', /* @ts-ignore */
193
208
  ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
194
209
  /** When true, collapses an extended FAB to icon-only on page scroll. */
195
- collapseOnScroll = input(false, /* @ts-ignore */
196
- ...(ngDevMode ? [{ debugName: "collapseOnScroll" }] : /* istanbul ignore next */ []));
197
- disabled = input(false, /* @ts-ignore */
198
- ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
210
+ collapseOnScroll = input(false, { ...(ngDevMode ? { debugName: "collapseOnScroll" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
211
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
199
212
  fabClick = output();
200
213
  /** Collapse state driven by scroll — only active when extended + collapseOnScroll. */
201
214
  _collapsed = signal(false, /* @ts-ignore */
@@ -225,6 +238,48 @@ class HubFabComponent {
225
238
  get _accent() {
226
239
  return resolveHubAccent(this.color());
227
240
  }
241
+ /**
242
+ * Keeps the FAB in the tab order (`0`), or takes it out while disabled (`-1`), the
243
+ * way a native button drops out of it — `pointer-events: none` only hides it from
244
+ * the pointer.
245
+ */
246
+ get _tabindex() {
247
+ return this.disabled() ? -1 : 0;
248
+ }
249
+ /**
250
+ * Conveys the disabled state to assistive tech, which a custom host tag cannot
251
+ * express through the native `disabled` attribute.
252
+ */
253
+ get _ariaDisabled() {
254
+ return this.disabled() ? 'true' : null;
255
+ }
256
+ /**
257
+ * The host element *is* the button surface — consumers project an icon into it,
258
+ * not a control — so activation is read here. `disabled` is re-checked in code
259
+ * because the `pointer-events: none` that backs it is a style: a programmatic
260
+ * `click()` (or a test) reaches the listener regardless.
261
+ */
262
+ _handleClick() {
263
+ if (this.disabled())
264
+ return;
265
+ this.fabClick.emit();
266
+ }
267
+ /**
268
+ * Emulates native button keyboard activation: Enter or Space triggers a click.
269
+ * Space additionally calls `preventDefault()` to stop the page from scrolling.
270
+ * @param event The originating keyboard event.
271
+ */
272
+ _onKeydown(event) {
273
+ if (this.disabled())
274
+ return;
275
+ const isSpace = event.key === ' ' || event.key === 'Spacebar';
276
+ if (event.key === 'Enter' || isSpace) {
277
+ if (isSpace) {
278
+ event.preventDefault();
279
+ }
280
+ event.currentTarget.click();
281
+ }
282
+ }
228
283
  ngOnInit() {
229
284
  if (!this.collapseOnScroll())
230
285
  return;
@@ -235,14 +290,19 @@ class HubFabComponent {
235
290
  });
236
291
  }
237
292
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubFabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
238
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: HubFabComponent, isStandalone: true, selector: "hub-fab", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, extended: { classPropertyName: "extended", publicName: "extended", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, collapseOnScroll: { classPropertyName: "collapseOnScroll", publicName: "collapseOnScroll", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fabClick: "fabClick" }, host: { properties: { "class": "_hostClass", "style.--hub-fab-accent": "_accent" }, classAttribute: "hub-fab" }, ngImport: i0, template: "<ng-content select=\"[slot=icon]\"></ng-content>\n\n@if (extended() && !_collapsed()) {\n\t<span class=\"hub-fab__label\">\n\t\t<ng-content select=\"[slot=label]\"></ng-content>\n\t</span>\n} @else if (!extended()) {\n\t<ng-content></ng-content>\n}\n", styles: [":where(.hub-fab){--hub-fab-size-mini: 2.5rem;--hub-fab-size-standard: 3.5rem;--hub-fab-size-large: 4.5rem;--hub-fab-border-radius: 50%;--hub-fab-shadow: var(--hub-sys-shadow-md, 0 .5rem 1rem rgba(0, 0, 0, .15));--hub-fab-shadow-hover: var(--hub-sys-shadow-lg, 0 1rem 3rem rgba(0, 0, 0, .175));--hub-fab-offset: var(--hub-ref-space-3, 1rem);--hub-fab-extended-height: 3.5rem;--hub-fab-extended-radius: 1.75rem;--hub-fab-extended-padding-x: 1.25rem;--hub-fab-transition: box-shadow .2s ease, transform .15s ease;--hub-fab-zindex: var(--hub-sys-zindex-fixed, 1030);--hub-fab-accent: var(--hub-sys-color-primary, #0d6efd)}.hub-fab{position:fixed;display:inline-flex;align-items:center;justify-content:center;width:var(--hub-fab-size-standard);height:var(--hub-fab-size-standard);border-radius:var(--hub-fab-border-radius);border:none;cursor:pointer;box-shadow:var(--hub-fab-shadow);z-index:var(--hub-fab-zindex);transition:var(--hub-fab-transition);background:var(--hub-fab-accent);color:var(--hub-ref-color-white, #ffffff);font-size:1.4rem}.hub-fab:hover{box-shadow:var(--hub-fab-shadow-hover);transform:translateY(-1px)}.hub-fab.hub-fab-disabled{opacity:.45;pointer-events:none}.hub-fab.hub-fab-extended{width:auto;height:var(--hub-fab-extended-height);border-radius:var(--hub-fab-extended-radius);padding-inline:var(--hub-fab-extended-padding-x);gap:var(--hub-ref-space-2, .5rem);font-size:.95rem;font-weight:var(--hub-ref-font-weight-semibold, 600)}.hub-fab-mini{width:var(--hub-fab-size-mini);height:var(--hub-fab-size-mini);font-size:var(--hub-ref-font-size-base, 1rem)}.hub-fab-large{width:var(--hub-fab-size-large);height:var(--hub-fab-size-large);font-size:1.75rem}.hub-fab-primary{background:var(--hub-sys-color-primary-default, var(--hub-sys-color-primary));color:var(--hub-sys-color-primary-on-default, #fff)}.hub-fab-secondary{background:var(--hub-sys-color-secondary-default, var(--hub-sys-color-secondary));color:var(--hub-sys-color-secondary-on-default, #fff)}.hub-fab-success{background:var(--hub-sys-color-success-default, var(--hub-sys-color-success));color:var(--hub-sys-color-success-on-default, #fff)}.hub-fab-danger{background:var(--hub-sys-color-danger-default, var(--hub-sys-color-danger));color:var(--hub-sys-color-danger-on-default, #fff)}.hub-fab-warning{background:var(--hub-sys-color-warning-default, var(--hub-sys-color-warning));color:var(--hub-sys-color-warning-on-default, #fff)}.hub-fab-info{background:var(--hub-sys-color-info-default, var(--hub-sys-color-info));color:var(--hub-sys-color-info-on-default, #fff)}.hub-speed-dial .hub-fab{position:static}.hub-fab-top-start{inset-block-start:var(--hub-fab-offset);inset-inline-start:var(--hub-fab-offset)}.hub-fab-top-center{inset-block-start:var(--hub-fab-offset);inset-inline-start:50%;transform:translate(-50%)}.hub-fab-top-end{inset-block-start:var(--hub-fab-offset);inset-inline-end:var(--hub-fab-offset)}.hub-fab-middle-start{inset-block-start:50%;inset-inline-start:var(--hub-fab-offset);transform:translateY(-50%)}.hub-fab-center{inset-block-start:50%;inset-inline-start:50%;transform:translate(-50%,-50%)}.hub-fab-middle-end{inset-block-start:50%;inset-inline-end:var(--hub-fab-offset);transform:translateY(-50%)}.hub-fab-bottom-start{inset-block-end:var(--hub-fab-offset);inset-inline-start:var(--hub-fab-offset)}.hub-fab-bottom-center{inset-block-end:var(--hub-fab-offset);inset-inline-start:50%;transform:translate(-50%)}.hub-fab-bottom-end{inset-block-end:var(--hub-fab-offset);inset-inline-end:var(--hub-fab-offset)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
293
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: HubFabComponent, isStandalone: true, selector: "hub-fab", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, extended: { classPropertyName: "extended", publicName: "extended", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, collapseOnScroll: { classPropertyName: "collapseOnScroll", publicName: "collapseOnScroll", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fabClick: "fabClick" }, host: { attributes: { "role": "button" }, listeners: { "click": "_handleClick()", "keydown": "_onKeydown($event)" }, properties: { "class": "_hostClass", "style.--hub-fab-accent": "_accent", "attr.tabindex": "_tabindex", "attr.aria-disabled": "_ariaDisabled" }, classAttribute: "hub-fab" }, ngImport: i0, template: "<ng-content select=\"[slot=icon]\"></ng-content>\n\n@if (extended() && !_collapsed()) {\n\t<span class=\"hub-fab__label\">\n\t\t<ng-content select=\"[slot=label]\"></ng-content>\n\t</span>\n} @else if (!extended()) {\n\t<ng-content></ng-content>\n}\n", styles: [":where(.hub-fab){--hub-fab-size-mini: 2.5rem;--hub-fab-size-standard: 3.5rem;--hub-fab-size-large: 4.5rem;--hub-fab-border-radius: 50%;--hub-fab-shadow: var(--hub-sys-shadow-md, 0 .5rem 1rem rgba(0, 0, 0, .15));--hub-fab-shadow-hover: var(--hub-sys-shadow-lg, 0 1rem 3rem rgba(0, 0, 0, .175));--hub-fab-offset: var(--hub-ref-space-3, 1rem);--hub-fab-extended-height: 3.5rem;--hub-fab-extended-radius: 1.75rem;--hub-fab-extended-padding-x: 1.25rem;--hub-fab-transition: box-shadow .2s ease, transform .15s ease;--hub-fab-zindex: var(--hub-sys-zindex-fixed, 1030);--hub-fab-accent: var(--hub-sys-color-primary, #0d6efd)}.hub-fab{position:fixed;display:inline-flex;align-items:center;justify-content:center;width:var(--hub-fab-size-standard);height:var(--hub-fab-size-standard);border-radius:var(--hub-fab-border-radius);border:none;cursor:pointer;box-shadow:var(--hub-fab-shadow);z-index:var(--hub-fab-zindex);transition:var(--hub-fab-transition);background:var(--hub-fab-accent);color:var(--hub-ref-color-white, #ffffff);font-size:1.4rem}.hub-fab:hover{box-shadow:var(--hub-fab-shadow-hover);transform:translateY(-1px)}.hub-fab.hub-fab-disabled{opacity:.45;pointer-events:none}.hub-fab.hub-fab-extended{width:auto;height:var(--hub-fab-extended-height);border-radius:var(--hub-fab-extended-radius);padding-inline:var(--hub-fab-extended-padding-x);gap:var(--hub-ref-space-2, .5rem);font-size:.95rem;font-weight:var(--hub-ref-font-weight-semibold, 600)}.hub-fab-mini{width:var(--hub-fab-size-mini);height:var(--hub-fab-size-mini);font-size:var(--hub-ref-font-size-base, 1rem)}.hub-fab-large{width:var(--hub-fab-size-large);height:var(--hub-fab-size-large);font-size:1.75rem}.hub-fab-primary{background:var(--hub-sys-color-primary-default, var(--hub-sys-color-primary));color:var(--hub-sys-color-primary-on-default, #fff)}.hub-fab-secondary{background:var(--hub-sys-color-secondary-default, var(--hub-sys-color-secondary));color:var(--hub-sys-color-secondary-on-default, #fff)}.hub-fab-success{background:var(--hub-sys-color-success-default, var(--hub-sys-color-success));color:var(--hub-sys-color-success-on-default, #fff)}.hub-fab-danger{background:var(--hub-sys-color-danger-default, var(--hub-sys-color-danger));color:var(--hub-sys-color-danger-on-default, #fff)}.hub-fab-warning{background:var(--hub-sys-color-warning-default, var(--hub-sys-color-warning));color:var(--hub-sys-color-warning-on-default, #fff)}.hub-fab-info{background:var(--hub-sys-color-info-default, var(--hub-sys-color-info));color:var(--hub-sys-color-info-on-default, #fff)}.hub-speed-dial .hub-fab{position:static}.hub-fab-top-start{inset-block-start:var(--hub-fab-offset);inset-inline-start:var(--hub-fab-offset)}.hub-fab-top-center{inset-block-start:var(--hub-fab-offset);inset-inline-start:50%;transform:translate(-50%)}.hub-fab-top-end{inset-block-start:var(--hub-fab-offset);inset-inline-end:var(--hub-fab-offset)}.hub-fab-middle-start{inset-block-start:50%;inset-inline-start:var(--hub-fab-offset);transform:translateY(-50%)}.hub-fab-center{inset-block-start:50%;inset-inline-start:50%;transform:translate(-50%,-50%)}.hub-fab-middle-end{inset-block-start:50%;inset-inline-end:var(--hub-fab-offset);transform:translateY(-50%)}.hub-fab-bottom-start{inset-block-end:var(--hub-fab-offset);inset-inline-start:var(--hub-fab-offset)}.hub-fab-bottom-center{inset-block-end:var(--hub-fab-offset);inset-inline-start:50%;transform:translate(-50%)}.hub-fab-bottom-end{inset-block-end:var(--hub-fab-offset);inset-inline-end:var(--hub-fab-offset)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
239
294
  }
240
295
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubFabComponent, decorators: [{
241
296
  type: Component,
242
297
  args: [{ selector: 'hub-fab', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
243
298
  class: 'hub-fab',
299
+ role: 'button',
244
300
  '[class]': '_hostClass',
245
- '[style.--hub-fab-accent]': '_accent'
301
+ '[style.--hub-fab-accent]': '_accent',
302
+ '[attr.tabindex]': '_tabindex',
303
+ '[attr.aria-disabled]': '_ariaDisabled',
304
+ '(click)': '_handleClick()',
305
+ '(keydown)': '_onKeydown($event)'
246
306
  }, encapsulation: ViewEncapsulation.None, template: "<ng-content select=\"[slot=icon]\"></ng-content>\n\n@if (extended() && !_collapsed()) {\n\t<span class=\"hub-fab__label\">\n\t\t<ng-content select=\"[slot=label]\"></ng-content>\n\t</span>\n} @else if (!extended()) {\n\t<ng-content></ng-content>\n}\n", styles: [":where(.hub-fab){--hub-fab-size-mini: 2.5rem;--hub-fab-size-standard: 3.5rem;--hub-fab-size-large: 4.5rem;--hub-fab-border-radius: 50%;--hub-fab-shadow: var(--hub-sys-shadow-md, 0 .5rem 1rem rgba(0, 0, 0, .15));--hub-fab-shadow-hover: var(--hub-sys-shadow-lg, 0 1rem 3rem rgba(0, 0, 0, .175));--hub-fab-offset: var(--hub-ref-space-3, 1rem);--hub-fab-extended-height: 3.5rem;--hub-fab-extended-radius: 1.75rem;--hub-fab-extended-padding-x: 1.25rem;--hub-fab-transition: box-shadow .2s ease, transform .15s ease;--hub-fab-zindex: var(--hub-sys-zindex-fixed, 1030);--hub-fab-accent: var(--hub-sys-color-primary, #0d6efd)}.hub-fab{position:fixed;display:inline-flex;align-items:center;justify-content:center;width:var(--hub-fab-size-standard);height:var(--hub-fab-size-standard);border-radius:var(--hub-fab-border-radius);border:none;cursor:pointer;box-shadow:var(--hub-fab-shadow);z-index:var(--hub-fab-zindex);transition:var(--hub-fab-transition);background:var(--hub-fab-accent);color:var(--hub-ref-color-white, #ffffff);font-size:1.4rem}.hub-fab:hover{box-shadow:var(--hub-fab-shadow-hover);transform:translateY(-1px)}.hub-fab.hub-fab-disabled{opacity:.45;pointer-events:none}.hub-fab.hub-fab-extended{width:auto;height:var(--hub-fab-extended-height);border-radius:var(--hub-fab-extended-radius);padding-inline:var(--hub-fab-extended-padding-x);gap:var(--hub-ref-space-2, .5rem);font-size:.95rem;font-weight:var(--hub-ref-font-weight-semibold, 600)}.hub-fab-mini{width:var(--hub-fab-size-mini);height:var(--hub-fab-size-mini);font-size:var(--hub-ref-font-size-base, 1rem)}.hub-fab-large{width:var(--hub-fab-size-large);height:var(--hub-fab-size-large);font-size:1.75rem}.hub-fab-primary{background:var(--hub-sys-color-primary-default, var(--hub-sys-color-primary));color:var(--hub-sys-color-primary-on-default, #fff)}.hub-fab-secondary{background:var(--hub-sys-color-secondary-default, var(--hub-sys-color-secondary));color:var(--hub-sys-color-secondary-on-default, #fff)}.hub-fab-success{background:var(--hub-sys-color-success-default, var(--hub-sys-color-success));color:var(--hub-sys-color-success-on-default, #fff)}.hub-fab-danger{background:var(--hub-sys-color-danger-default, var(--hub-sys-color-danger));color:var(--hub-sys-color-danger-on-default, #fff)}.hub-fab-warning{background:var(--hub-sys-color-warning-default, var(--hub-sys-color-warning));color:var(--hub-sys-color-warning-on-default, #fff)}.hub-fab-info{background:var(--hub-sys-color-info-default, var(--hub-sys-color-info));color:var(--hub-sys-color-info-on-default, #fff)}.hub-speed-dial .hub-fab{position:static}.hub-fab-top-start{inset-block-start:var(--hub-fab-offset);inset-inline-start:var(--hub-fab-offset)}.hub-fab-top-center{inset-block-start:var(--hub-fab-offset);inset-inline-start:50%;transform:translate(-50%)}.hub-fab-top-end{inset-block-start:var(--hub-fab-offset);inset-inline-end:var(--hub-fab-offset)}.hub-fab-middle-start{inset-block-start:50%;inset-inline-start:var(--hub-fab-offset);transform:translateY(-50%)}.hub-fab-center{inset-block-start:50%;inset-inline-start:50%;transform:translate(-50%,-50%)}.hub-fab-middle-end{inset-block-start:50%;inset-inline-end:var(--hub-fab-offset);transform:translateY(-50%)}.hub-fab-bottom-start{inset-block-end:var(--hub-fab-offset);inset-inline-start:var(--hub-fab-offset)}.hub-fab-bottom-center{inset-block-end:var(--hub-fab-offset);inset-inline-start:50%;transform:translate(-50%)}.hub-fab-bottom-end{inset-block-end:var(--hub-fab-offset);inset-inline-end:var(--hub-fab-offset)}\n"] }]
247
307
  }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], extended: [{ type: i0.Input, args: [{ isSignal: true, alias: "extended", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], collapseOnScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseOnScroll", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], fabClick: [{ type: i0.Output, args: ["fabClick"] }] } });
248
308
 
@@ -250,6 +310,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
250
310
  * FAB that expands a stack of HubSpeedDialItemComponent children on click or hover.
251
311
  * Supports 4 expansion directions and all 9 FAB viewport positions.
252
312
  * Closes automatically on Escape key press.
313
+ *
314
+ * The hover trigger is watched on the host, not on the trigger button: the host box holds
315
+ * the button, the action items and the gap between them, so travelling from the trigger to
316
+ * an item never leaves it. On the button, that trip is a `mouseleave` and the menu is gone
317
+ * before the pointer arrives.
253
318
  */
254
319
  class HubSpeedDialComponent {
255
320
  color = input('primary', /* @ts-ignore */
@@ -298,6 +363,14 @@ class HubSpeedDialComponent {
298
363
  .subscribe(() => this.close());
299
364
  }
300
365
  }
366
+ _onHostEnter() {
367
+ if (this.trigger() === 'hover')
368
+ this.open();
369
+ }
370
+ _onHostLeave() {
371
+ if (this.trigger() === 'hover')
372
+ this.close();
373
+ }
301
374
  /** Toggle the speed dial open/closed. */
302
375
  toggle() {
303
376
  this.isOpen() ? this.close() : this.open();
@@ -313,14 +386,16 @@ class HubSpeedDialComponent {
313
386
  this.closed.emit();
314
387
  }
315
388
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubSpeedDialComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
316
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: HubSpeedDialComponent, isStandalone: true, selector: "hub-speed-dial", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", 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", opened: "opened", closed: "closed" }, host: { properties: { "class": "_hostClass" }, classAttribute: "hub-speed-dial" }, ngImport: i0, template: "<button\n\tclass=\"hub-fab\"\n\t[class]=\"'hub-fab-' + color() + ' hub-fab-' + size()\"\n\t[style.--hub-fab-accent]=\"_accent\"\n\t(click)=\"trigger() === 'click' && toggle()\"\n\t(mouseenter)=\"trigger() === 'hover' && open()\"\n\t(mouseleave)=\"trigger() === 'hover' && close()\"\n\ttype=\"button\"\n\t[attr.aria-expanded]=\"isOpen()\"\n\taria-haspopup=\"true\"\n>\n\t<ng-content select=\"[hubTrigger]\"></ng-content>\n</button>\n\n@if (isOpen()) {\n\t<div class=\"hub-speed-dial__actions\" [attr.data-direction]=\"direction()\">\n\t\t<ng-content></ng-content>\n\t</div>\n}\n", styles: [":where(:host){--hub-speed-dial-gap: .625rem;--hub-speed-dial-zindex: var(--hub-sys-zindex-fixed, 1030);--hub-speed-dial-animation: .2s ease}:host{position:fixed;display:flex;flex-direction:column-reverse;align-items:center;gap:var(--hub-speed-dial-gap);z-index:var(--hub-speed-dial-zindex)}.hub-speed-dial__actions{display:flex;flex-direction:column-reverse;align-items:center;gap:var(--hub-speed-dial-gap);animation:hub-sd-fade-in var(--hub-speed-dial-animation) both}:host(.hub-speed-dial-top-start){inset-block-start:1rem;inset-inline-start:1rem;flex-direction:column;align-items:flex-start}:host(.hub-speed-dial-top-end){inset-block-start:1rem;inset-inline-end:1rem;flex-direction:column;align-items:flex-end}:host(.hub-speed-dial-bottom-start){inset-block-end:1rem;inset-inline-start:1rem;align-items:flex-start}:host(.hub-speed-dial-bottom-end){inset-block-end:1rem;inset-inline-end:1rem;align-items:flex-end}:host(.hub-speed-dial-center){inset-block-start:50%;inset-inline-start:50%;transform:translate(-50%,-50%)}:host(.hub-speed-dial-left){flex-direction:row-reverse}:host(.hub-speed-dial-left) .hub-speed-dial__actions{flex-direction:row-reverse}:host(.hub-speed-dial-right){flex-direction:row}:host(.hub-speed-dial-right) .hub-speed-dial__actions{flex-direction:row}@keyframes hub-sd-fade-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
389
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: HubSpeedDialComponent, isStandalone: true, selector: "hub-speed-dial", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", 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", opened: "opened", closed: "closed" }, host: { listeners: { "mouseenter": "_onHostEnter()", "mouseleave": "_onHostLeave()" }, properties: { "class": "_hostClass" }, classAttribute: "hub-speed-dial" }, ngImport: i0, template: "<button\n\tclass=\"hub-fab\"\n\t[class]=\"'hub-fab-' + color() + ' hub-fab-' + size()\"\n\t[style.--hub-fab-accent]=\"_accent\"\n\t(click)=\"trigger() === 'click' && toggle()\"\n\ttype=\"button\"\n\t[attr.aria-expanded]=\"isOpen()\"\n\taria-haspopup=\"true\"\n>\n\t<ng-content select=\"[hubTrigger]\"></ng-content>\n</button>\n\n@if (isOpen()) {\n\t<div class=\"hub-speed-dial__actions\" [attr.data-direction]=\"direction()\">\n\t\t<ng-content></ng-content>\n\t</div>\n}\n", styles: [":where(:host){--hub-speed-dial-gap: .625rem;--hub-speed-dial-zindex: var(--hub-sys-zindex-fixed, 1030);--hub-speed-dial-animation: .2s ease}:host{position:fixed;display:flex;flex-direction:column-reverse;align-items:center;gap:var(--hub-speed-dial-gap);z-index:var(--hub-speed-dial-zindex)}.hub-speed-dial__actions{display:flex;flex-direction:column-reverse;align-items:center;gap:var(--hub-speed-dial-gap);animation:hub-sd-fade-in var(--hub-speed-dial-animation) both}:host(.hub-speed-dial-top-start){inset-block-start:1rem;inset-inline-start:1rem;flex-direction:column;align-items:flex-start}:host(.hub-speed-dial-top-end){inset-block-start:1rem;inset-inline-end:1rem;flex-direction:column;align-items:flex-end}:host(.hub-speed-dial-bottom-start){inset-block-end:1rem;inset-inline-start:1rem;align-items:flex-start}:host(.hub-speed-dial-bottom-end){inset-block-end:1rem;inset-inline-end:1rem;align-items:flex-end}:host(.hub-speed-dial-center){inset-block-start:50%;inset-inline-start:50%;transform:translate(-50%,-50%)}:host(.hub-speed-dial-left){flex-direction:row-reverse}:host(.hub-speed-dial-left) .hub-speed-dial__actions{flex-direction:row-reverse}:host(.hub-speed-dial-right){flex-direction:row}:host(.hub-speed-dial-right) .hub-speed-dial__actions{flex-direction:row}@keyframes hub-sd-fade-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
317
390
  }
318
391
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubSpeedDialComponent, decorators: [{
319
392
  type: Component,
320
393
  args: [{ selector: 'hub-speed-dial', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
321
394
  class: 'hub-speed-dial',
322
- '[class]': '_hostClass'
323
- }, template: "<button\n\tclass=\"hub-fab\"\n\t[class]=\"'hub-fab-' + color() + ' hub-fab-' + size()\"\n\t[style.--hub-fab-accent]=\"_accent\"\n\t(click)=\"trigger() === 'click' && toggle()\"\n\t(mouseenter)=\"trigger() === 'hover' && open()\"\n\t(mouseleave)=\"trigger() === 'hover' && close()\"\n\ttype=\"button\"\n\t[attr.aria-expanded]=\"isOpen()\"\n\taria-haspopup=\"true\"\n>\n\t<ng-content select=\"[hubTrigger]\"></ng-content>\n</button>\n\n@if (isOpen()) {\n\t<div class=\"hub-speed-dial__actions\" [attr.data-direction]=\"direction()\">\n\t\t<ng-content></ng-content>\n\t</div>\n}\n", styles: [":where(:host){--hub-speed-dial-gap: .625rem;--hub-speed-dial-zindex: var(--hub-sys-zindex-fixed, 1030);--hub-speed-dial-animation: .2s ease}:host{position:fixed;display:flex;flex-direction:column-reverse;align-items:center;gap:var(--hub-speed-dial-gap);z-index:var(--hub-speed-dial-zindex)}.hub-speed-dial__actions{display:flex;flex-direction:column-reverse;align-items:center;gap:var(--hub-speed-dial-gap);animation:hub-sd-fade-in var(--hub-speed-dial-animation) both}:host(.hub-speed-dial-top-start){inset-block-start:1rem;inset-inline-start:1rem;flex-direction:column;align-items:flex-start}:host(.hub-speed-dial-top-end){inset-block-start:1rem;inset-inline-end:1rem;flex-direction:column;align-items:flex-end}:host(.hub-speed-dial-bottom-start){inset-block-end:1rem;inset-inline-start:1rem;align-items:flex-start}:host(.hub-speed-dial-bottom-end){inset-block-end:1rem;inset-inline-end:1rem;align-items:flex-end}:host(.hub-speed-dial-center){inset-block-start:50%;inset-inline-start:50%;transform:translate(-50%,-50%)}:host(.hub-speed-dial-left){flex-direction:row-reverse}:host(.hub-speed-dial-left) .hub-speed-dial__actions{flex-direction:row-reverse}:host(.hub-speed-dial-right){flex-direction:row}:host(.hub-speed-dial-right) .hub-speed-dial__actions{flex-direction:row}@keyframes hub-sd-fade-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}\n"] }]
395
+ '[class]': '_hostClass',
396
+ '(mouseenter)': '_onHostEnter()',
397
+ '(mouseleave)': '_onHostLeave()'
398
+ }, template: "<button\n\tclass=\"hub-fab\"\n\t[class]=\"'hub-fab-' + color() + ' hub-fab-' + size()\"\n\t[style.--hub-fab-accent]=\"_accent\"\n\t(click)=\"trigger() === 'click' && toggle()\"\n\ttype=\"button\"\n\t[attr.aria-expanded]=\"isOpen()\"\n\taria-haspopup=\"true\"\n>\n\t<ng-content select=\"[hubTrigger]\"></ng-content>\n</button>\n\n@if (isOpen()) {\n\t<div class=\"hub-speed-dial__actions\" [attr.data-direction]=\"direction()\">\n\t\t<ng-content></ng-content>\n\t</div>\n}\n", styles: [":where(:host){--hub-speed-dial-gap: .625rem;--hub-speed-dial-zindex: var(--hub-sys-zindex-fixed, 1030);--hub-speed-dial-animation: .2s ease}:host{position:fixed;display:flex;flex-direction:column-reverse;align-items:center;gap:var(--hub-speed-dial-gap);z-index:var(--hub-speed-dial-zindex)}.hub-speed-dial__actions{display:flex;flex-direction:column-reverse;align-items:center;gap:var(--hub-speed-dial-gap);animation:hub-sd-fade-in var(--hub-speed-dial-animation) both}:host(.hub-speed-dial-top-start){inset-block-start:1rem;inset-inline-start:1rem;flex-direction:column;align-items:flex-start}:host(.hub-speed-dial-top-end){inset-block-start:1rem;inset-inline-end:1rem;flex-direction:column;align-items:flex-end}:host(.hub-speed-dial-bottom-start){inset-block-end:1rem;inset-inline-start:1rem;align-items:flex-start}:host(.hub-speed-dial-bottom-end){inset-block-end:1rem;inset-inline-end:1rem;align-items:flex-end}:host(.hub-speed-dial-center){inset-block-start:50%;inset-inline-start:50%;transform:translate(-50%,-50%)}:host(.hub-speed-dial-left){flex-direction:row-reverse}:host(.hub-speed-dial-left) .hub-speed-dial__actions{flex-direction:row-reverse}:host(.hub-speed-dial-right){flex-direction:row}:host(.hub-speed-dial-right) .hub-speed-dial__actions{flex-direction:row}@keyframes hub-sd-fade-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}\n"] }]
324
399
  }], ctorParameters: () => [], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", 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"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
325
400
 
326
401
  /**
@@ -328,7 +403,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
328
403
  * Emits itemClick when activated. Supports an optional label tooltip.
329
404
  */
330
405
  class HubSpeedDialItemComponent {
331
- /** Icon character or ligature string displayed in the action button. */
406
+ /** CSS class of the icon rendered in the action button (e.g. `'bi bi-pencil'`). */
332
407
  icon = input.required(/* @ts-ignore */
333
408
  ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
334
409
  /** Tooltip label shown next to the action button. */
@@ -336,8 +411,14 @@ class HubSpeedDialItemComponent {
336
411
  ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
337
412
  color = input('default', /* @ts-ignore */
338
413
  ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
339
- disabled = input(false, /* @ts-ignore */
340
- ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
414
+ /**
415
+ * Makes the action button inert.
416
+ *
417
+ * Transformed, so the bare HTML form works: `<hub-speed-dial-item disabled>` passes the
418
+ * empty string an attribute without a value carries, which an untransformed
419
+ * `input(false)` rejects at compile time.
420
+ */
421
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
341
422
  itemClick = output();
342
423
  /**
343
424
  * The semantic accent painted on the action button through its
@@ -405,14 +486,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
405
486
  class HubDropdownItemComponent {
406
487
  color = input('default', /* @ts-ignore */
407
488
  ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
408
- /** Optional icon character or ligature displayed before the label. */
489
+ /** Optional CSS class of the icon rendered before the label (e.g. `'bi bi-pencil'`). */
409
490
  icon = input(/* @ts-ignore */
410
491
  ...(ngDevMode ? [undefined, { debugName: "icon" }] : /* istanbul ignore next */ []));
411
- disabled = input(false, /* @ts-ignore */
412
- ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
492
+ /**
493
+ * Makes the item inert.
494
+ *
495
+ * Transformed, so the bare HTML form works: `<hub-dropdown-item disabled>` passes the
496
+ * empty string an attribute without a value carries, which an untransformed
497
+ * `input(false)` rejects at compile time. Same for {@link selected}.
498
+ */
499
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
413
500
  /** Shows a checkmark indicator when selected. */
414
- selected = input(false, /* @ts-ignore */
415
- ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
501
+ selected = input(false, { ...(ngDevMode ? { debugName: "selected" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
416
502
  itemClick = output();
417
503
  get _hostClass() {
418
504
  return [
@@ -503,11 +589,15 @@ class HubDropdownDirective {
503
589
  ...(ngDevMode ? [{ debugName: "placement" }] : /* istanbul ignore next */ []));
504
590
  trigger = input('click', /* @ts-ignore */
505
591
  ...(ngDevMode ? [{ debugName: "trigger" }] : /* istanbul ignore next */ []));
506
- /** When true, any click inside the panel content closes the dropdown. */
507
- closeOnSelect = input(true, /* @ts-ignore */
508
- ...(ngDevMode ? [{ debugName: "closeOnSelect" }] : /* istanbul ignore next */ []));
509
- disabled = input(false, /* @ts-ignore */
510
- ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
592
+ /**
593
+ * When true, any click inside the panel content closes the dropdown.
594
+ *
595
+ * Transformed, so the bare HTML form works: `closeOnSelect` on its own passes the empty
596
+ * string an attribute without a value carries, which an untransformed `input(true)`
597
+ * rejects at compile time. Same for {@link disabled}.
598
+ */
599
+ closeOnSelect = input(true, { ...(ngDevMode ? { debugName: "closeOnSelect" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
600
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
511
601
  /** Vertical offset in pixels between the trigger and the panel. */
512
602
  offsetY = input(4, /* @ts-ignore */
513
603
  ...(ngDevMode ? [{ debugName: "offsetY" }] : /* istanbul ignore next */ []));
@@ -518,6 +608,23 @@ class HubDropdownDirective {
518
608
  opened = output();
519
609
  closed = output();
520
610
  _overlayRef = null;
611
+ /**
612
+ * How long, in milliseconds, the pointer is allowed to be over neither the trigger nor
613
+ * the panel before a hover dropdown closes. The panel is body-level and sits `offsetY`
614
+ * away from its trigger, so leaving the trigger is not yet a dismissal — leaving it and
615
+ * arriving nowhere is.
616
+ */
617
+ static HOVER_GRACE_MS = 150;
618
+ _hoverCloseTimer = null;
619
+ /** Enter/leave listeners on the attached panel, live only while a hover dropdown is open. */
620
+ _panelHover = null;
621
+ /**
622
+ * Everything open() subscribes to for this cycle only. take(1) retires each one when it
623
+ * fires, but a dropdown closed by Escape, by a scroll or from code never fires them: they
624
+ * would survive holding the detached panel and close the NEXT panel on the first click
625
+ * inside it, which is the very thing closeOnSelect: false is meant to prevent.
626
+ */
627
+ _openSubs = null;
521
628
  _el = inject((ElementRef));
522
629
  _vcr = inject(ViewContainerRef);
523
630
  _overlay = inject(OverlayService);
@@ -539,6 +646,7 @@ class HubDropdownDirective {
539
646
  if (openDropdown === this) {
540
647
  openDropdown = null;
541
648
  }
649
+ this._stopHoverTracking();
542
650
  this._overlayRef?.detach();
543
651
  this._overlayRef?.dispose();
544
652
  this._overlayRef = null;
@@ -556,27 +664,48 @@ class HubDropdownDirective {
556
664
  panelClasses.push(this.panelClass());
557
665
  this._overlayRef = this._overlay.create({ positionStrategy, panelClass: panelClasses });
558
666
  const panelEl = this._overlayRef.attach(this.tpl(), this._vcr);
559
- // Close on click-outside via backdrop
560
- this._overlayRef.onBackdropClick(() => this.close());
667
+ this._openSubs = new Subscription();
561
668
  // Close on click-inside when closeOnSelect is true
562
669
  if (this.closeOnSelect() && panelEl) {
563
- fromEvent(panelEl, 'click')
670
+ this._openSubs.add(fromEvent(panelEl, 'click')
564
671
  .pipe(take(1), takeUntilDestroyed(this._destroyRef))
565
- .subscribe(() => this.close());
672
+ .subscribe(() => this.close()));
673
+ }
674
+ // The panel is body-level, so the pointer entering it is a leave as far as the
675
+ // trigger is concerned. Tracked here so that reaching the panel keeps the dropdown
676
+ // open, and only leaving the panel too starts the countdown again.
677
+ if (this.trigger() === 'hover' && panelEl) {
678
+ this._panelHover = new Subscription();
679
+ this._panelHover.add(fromEvent(panelEl, 'mouseenter').subscribe(() => this._cancelScheduledClose()));
680
+ this._panelHover.add(fromEvent(panelEl, 'mouseleave').subscribe(() => this._scheduleHoverClose()));
566
681
  }
567
682
  this.isOpen.set(true);
568
683
  this.opened.emit();
569
684
  // Close on scroll so the panel stays aligned with the trigger
570
- fromEvent(this._document, 'scroll', { passive: true, capture: true })
685
+ this._openSubs.add(fromEvent(this._document, 'scroll', { passive: true, capture: true })
571
686
  .pipe(take(1), takeUntilDestroyed(this._destroyRef))
572
- .subscribe(() => this.close());
573
- // Click-outside detection (document-level)
574
- fromEvent(this._document, 'click')
575
- .pipe(filter((e) => !this._el.nativeElement.contains(e.target) && !!this._overlayRef?.hasAttached()), take(1), takeUntilDestroyed(this._destroyRef))
576
- .subscribe(() => this.close());
687
+ .subscribe(() => this.close()));
688
+ // Click-outside detection (document-level). The overlay is mounted without a backdrop
689
+ // — nothing dims or blocks the page behind an open menu — so this listener is the only
690
+ // thing that closes it on an outside click. The panel has to be named explicitly:
691
+ // it hangs off the body, never inside the trigger, so without this every click on
692
+ // a menu item would read as a click outside and close the dropdown — whatever
693
+ // `closeOnSelect` says.
694
+ this._openSubs.add(fromEvent(this._document, 'click')
695
+ .pipe(filter((e) => !this._el.nativeElement.contains(e.target) &&
696
+ !panelEl?.contains(e.target) &&
697
+ !!this._overlayRef?.hasAttached()), take(1), takeUntilDestroyed(this._destroyRef))
698
+ .subscribe(() => this.close()));
577
699
  }
578
700
  /** Close the dropdown and destroy the overlay. */
579
701
  close() {
702
+ // Before the guard: a pending hover countdown outlives whatever closed the dropdown
703
+ // first (Escape, a scroll, a call from code), and would otherwise fire into the next
704
+ // open one.
705
+ this._stopHoverTracking();
706
+ // Same reason: these hold the panel that is about to be detached.
707
+ this._openSubs?.unsubscribe();
708
+ this._openSubs = null;
580
709
  if (!this.isOpen())
581
710
  return;
582
711
  if (openDropdown === this) {
@@ -599,12 +728,41 @@ class HubDropdownDirective {
599
728
  this.toggle();
600
729
  }
601
730
  _onHostEnter() {
602
- if (this.trigger() === 'hover')
603
- this.open();
731
+ if (this.trigger() !== 'hover')
732
+ return;
733
+ this._cancelScheduledClose();
734
+ this.open();
604
735
  }
736
+ /**
737
+ * Leaving the trigger only starts a countdown. Closing here and now would make the
738
+ * panel unreachable: it is body-level and offset from the trigger, so the pointer has
739
+ * to cross a gap that belongs to neither of them.
740
+ */
605
741
  _onHostLeave() {
606
- if (this.trigger() === 'hover')
742
+ if (this.trigger() !== 'hover')
743
+ return;
744
+ this._scheduleHoverClose();
745
+ }
746
+ /** Arms the grace period, replacing any countdown already running. */
747
+ _scheduleHoverClose() {
748
+ this._cancelScheduledClose();
749
+ this._hoverCloseTimer = setTimeout(() => {
750
+ this._hoverCloseTimer = null;
607
751
  this.close();
752
+ }, HubDropdownDirective.HOVER_GRACE_MS);
753
+ }
754
+ /** Disarms the grace period, because the pointer arrived somewhere that counts as inside. */
755
+ _cancelScheduledClose() {
756
+ if (this._hoverCloseTimer === null)
757
+ return;
758
+ clearTimeout(this._hoverCloseTimer);
759
+ this._hoverCloseTimer = null;
760
+ }
761
+ /** Drops both halves of the hover bookkeeping: the countdown and the panel listeners. */
762
+ _stopHoverTracking() {
763
+ this._cancelScheduledClose();
764
+ this._panelHover?.unsubscribe();
765
+ this._panelHover = null;
608
766
  }
609
767
  /**
610
768
  * Translates HubDropdownPlacement tokens to ConnectionPosition arrays.
@@ -1 +1 @@
1
- {"version":3,"file":"ng-hub-ui-buttons.mjs","sources":["../../../projects/buttons/src/lib/tokens/dropdown.token.ts","../../../projects/buttons/src/lib/components/btn/button.component.ts","../../../projects/buttons/src/lib/components/btn/button.component.html","../../../projects/buttons/src/lib/components/fab/fab.component.ts","../../../projects/buttons/src/lib/components/fab/fab.component.html","../../../projects/buttons/src/lib/components/speed-dial/speed-dial.component.ts","../../../projects/buttons/src/lib/components/speed-dial/speed-dial.component.html","../../../projects/buttons/src/lib/components/speed-dial/speed-dial-item/speed-dial-item.component.ts","../../../projects/buttons/src/lib/components/speed-dial/speed-dial-item/speed-dial-item.component.html","../../../projects/buttons/src/lib/components/dropdown-panel/dropdown-panel.component.ts","../../../projects/buttons/src/lib/components/dropdown-item/dropdown-item.component.ts","../../../projects/buttons/src/lib/components/dropdown-item/dropdown-item.component.html","../../../projects/buttons/src/lib/components/dropdown-divider/dropdown-divider.component.ts","../../../projects/buttons/src/lib/components/dropdown-header/dropdown-header.component.ts","../../../projects/buttons/src/lib/directives/dropdown.directive.ts","../../../projects/buttons/src/lib/integrations/actions.types.ts","../../../projects/buttons/src/lib/integrations/actions-cell.component.ts","../../../projects/buttons/src/lib/integrations/actions-adapter.ts","../../../projects/buttons/src/public-api.ts","../../../projects/buttons/src/ng-hub-ui-buttons.ts"],"sourcesContent":["import { InjectionToken, Signal } from '@angular/core';\n\n/**\n * Context shared between HubDropdownDirective and its panel/item descendants.\n * Injected by the directive; consumed by HubDropdownPanelComponent and\n * HubDropdownItemComponent to implement closeOnSelect without prop drilling.\n */\nexport interface DropdownContext {\n\t/** Whether clicking an item should close the dropdown. */\n\treadonly closeOnSelect: Signal<boolean>;\n\t/** Imperatively close the dropdown. */\n\tclose(): void;\n}\n\n/** Injection token for DropdownContext. */\nexport const DROPDOWN_CONTEXT = new InjectionToken<DropdownContext>('HubDropdownContext');\n","import { booleanAttribute, ChangeDetectionStrategy, Component, ElementRef, inject, input } from '@angular/core';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { HubBtnSize, HubBtnVariant, HubSemanticColor } from '../../models/button.types';\n\n/**\n * Styled button. Applies `hub-btn` CSS classes computed from signal inputs and\n * renders an optional loading spinner around the projected content.\n *\n * Usable in two interchangeable forms from the same class:\n * - As an element: `<hub-button variant=\"solid\" color=\"primary\">Save</hub-button>`.\n * - As an attribute on any host: `<button hubButton>Save</button>` / `<a hubButton href=\"…\">Link</a>`.\n *\n * Prefer the attribute form on a native `<button>` / `<a>` when you need real button\n * semantics (focus, keyboard activation, form submission). The `<hub-button>` **element**\n * form is only a styling host — a component cannot swap its own host tag for a native\n * `<button>` — so it self-advertises `role=\"button\"`, a focusable `tabindex`, and\n * Enter/Space keyboard activation to stay accessible. The `[hubButton]` attribute form on\n * a native `<button>`/`<a>` adds **none** of these bindings (the host is already\n * interactive; a redundant `role`/`tabindex` would be harmful).\n *\n * **Accessibility caveat:** an element-form `<hub-button>` now reports `role=\"button\"`,\n * so it must not be nested inside another interactive element (a `<button>`, `<a>` or any\n * host that is itself a control), which would produce an invalid nested-interactive tree.\n *\n * **Icons:** project whatever you want as content — the button is icon-library\n * agnostic. The icon's position follows the markup order, and the label/icon gap\n * is the `--hub-button-gap` token:\n *\n * ```html\n * <button hubButton><hub-icon name=\"floppy-disk\" /> Save</button>\n * <button hubButton>Next <hub-icon name=\"arrow-right\" /></button>\n * <button hubButton aria-label=\"Settings\"><hub-icon name=\"gear\" /></button>\n * ```\n */\n@Component({\n\tselector: 'hub-button, [hubButton]',\n\tstandalone: true,\n\ttemplateUrl: './button.component.html',\n\tstyleUrl: './button.component.scss',\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: {\n\t\tclass: 'hub-btn',\n\t\t'[class]': '_hostClass',\n\t\t'[style.--hub-btn-accent]': '_accent',\n\t\t'[attr.disabled]': '_disabledAttr',\n\t\t'[attr.aria-busy]': '_ariaBusy',\n\t\t'[attr.aria-disabled]': '_ariaDisabled',\n\t\t'[attr.role]': '_role',\n\t\t'[attr.tabindex]': '_tabindex',\n\t\t'(keydown)': '_onKeydown($event)'\n\t}\n})\nexport class HubButtonComponent {\n\t/**\n\t * Whether this instance renders as the `<hub-button>` element (vs `[hubButton]` on a\n\t * native host). Read once from the host tag at construction — a static host fact that\n\t * is available immediately (unlike input signals, which are not populated in the\n\t * constructor). Gates the a11y host bindings so they only apply to the element form.\n\t */\n\tprivate readonly _isElementForm = inject(ElementRef).nativeElement.tagName === 'HUB-BUTTON';\n\n\t/** Visual style of the button. */\n\tvariant = input<HubBtnVariant>('solid');\n\n\t/** Semantic color token. */\n\tcolor = input<HubSemanticColor>('primary');\n\n\t/** Size token. */\n\tsize = input<HubBtnSize>('md');\n\n\t/**\n\t * When true, shows the spinner and marks the button **busy and disabled**: it\n\t * reflects `aria-busy=\"true\"`, becomes non-focusable and inert to pointer and\n\t * keyboard, and (like {@link disabled}) reflects the native `disabled` attribute\n\t * so an in-flight submit button cannot be triggered twice.\n\t */\n\tloading = input(false, { transform: booleanAttribute });\n\n\t/**\n\t * Mirrors the native disabled attribute on the host element.\n\t *\n\t * Transformed, so the bare HTML form works: `<button hubButton disabled>` passes the\n\t * empty string an attribute without a value carries, which an untransformed\n\t * `input(false)` rejects at compile time — on the very spelling the name promises.\n\t */\n\tdisabled = input(false, { transform: booleanAttribute });\n\n\t/**\n\t * True while the button must not respond to interaction — either explicitly\n\t * {@link disabled} or busy {@link loading}. Drives the native `disabled`\n\t * reflection, the tab-order removal and the keyboard-activation guard so both\n\t * states are inert through a single source of truth.\n\t */\n\tprivate get _isInert(): boolean {\n\t\treturn this.disabled() || this.loading();\n\t}\n\n\t/** Computed CSS classes applied to the host element via the `[class]` host binding. */\n\tprotected get _hostClass(): string {\n\t\treturn [\n\t\t\t`hub-btn-${this.variant()}`,\n\t\t\t`hub-btn-${this.color()}`,\n\t\t\t`hub-btn-${this.size()}`,\n\t\t\tthis.loading() ? 'hub-btn-loading' : '',\n\t\t\tthis.disabled() ? 'hub-btn-disabled' : ''\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' ');\n\t}\n\n\t/**\n\t * The single semantic accent consumed by the stylesheet (`--hub-btn-accent`),\n\t * from which every visual role (emphasis / subtle / on) is derived at runtime.\n\t *\n\t * Accepts ANY colour: a bareword (a built-in semantic name, a host-registered\n\t * accent or a CSS named colour) resolves to its `--hub-sys-color-<name>` token\n\t * with the bareword itself as the raw fallback, so unregistered names still\n\t * paint; a literal (`#hex`, `rgb()`, `oklch()`, `var(...)`) is passed through\n\t * unchanged. The built-in `hub-btn-<color>` appearance classes remain in place.\n\t */\n\tprotected get _accent(): string | null {\n\t\treturn resolveHubAccent(this.color());\n\t}\n\n\t/** Reflects the inert state (disabled or loading) as the native `disabled` attribute. */\n\tprotected get _disabledAttr(): true | null {\n\t\treturn this._isInert ? true : null;\n\t}\n\n\t/** Announces the busy state to assistive tech while loading. */\n\tprotected get _ariaBusy(): 'true' | null {\n\t\treturn this.loading() ? 'true' : null;\n\t}\n\n\t/**\n\t * Conveys the inert state to assistive tech on the element form, whose custom\n\t * host tag does not natively expose `disabled`. Bound to nothing for the\n\t * attribute form (its native host already exposes the state).\n\t */\n\tprotected get _ariaDisabled(): 'true' | null {\n\t\treturn this._isElementForm && this._isInert ? 'true' : null;\n\t}\n\n\t/**\n\t * Advertises `role=\"button\"` for the element form only. The attribute form binds\n\t * nothing (its native host already exposes the correct role).\n\t */\n\tprotected get _role(): 'button' | null {\n\t\treturn this._isElementForm ? 'button' : null;\n\t}\n\n\t/**\n\t * Makes the element form keyboard-focusable (`0`), or removes it from the tab order\n\t * when inert — disabled or loading (`-1`). Bound to nothing for the attribute form.\n\t */\n\tprotected get _tabindex(): number | null {\n\t\tif (!this._isElementForm) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this._isInert ? -1 : 0;\n\t}\n\n\t/**\n\t * Emulates native button keyboard activation for the element form: Enter or Space\n\t * triggers a click. Space additionally calls `preventDefault()` to stop the page from\n\t * scrolling. No-op for the attribute form (the native host already handles keys) and\n\t * while inert (disabled or loading).\n\t * @param event The originating keyboard event.\n\t */\n\tprotected _onKeydown(event: KeyboardEvent): void {\n\t\tif (!this._isElementForm || this._isInert) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isSpace = event.key === ' ' || event.key === 'Spacebar';\n\n\t\tif (event.key === 'Enter' || isSpace) {\n\t\t\tif (isSpace) {\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\n\t\t\t(event.currentTarget as HTMLElement).click();\n\t\t}\n\t}\n}\n","@if (loading()) {\n\t<span class=\"hub-btn__spinner\" aria-hidden=\"true\"></span>\n}\n<ng-content></ng-content>\n","import {\n\tChangeDetectionStrategy,\n\tComponent,\n\tDestroyRef,\n\tOnInit,\n\tViewEncapsulation,\n\tinject,\n\tinput,\n\toutput,\n\tsignal\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { fromEvent } from 'rxjs';\nimport { debounceTime } from 'rxjs/operators';\nimport { HubFabPosition, HubFabSize, HubSemanticColor } from '../../models/button.types';\n\n/**\n * Floating Action Button component. Renders fixed in the viewport at the given position.\n * Supports circular and extended (pill with label) variants.\n * When collapseOnScroll is true, an extended FAB collapses to icon-only after 50px scroll.\n * Uses inset-inline-* / inset-block-* CSS logical properties for RTL support.\n */\n@Component({\n\tselector: 'hub-fab',\n\tstandalone: true,\n\ttemplateUrl: './fab.component.html',\n\tstyleUrl: './fab.component.scss',\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: {\n\t\tclass: 'hub-fab',\n\t\t'[class]': '_hostClass',\n\t\t'[style.--hub-fab-accent]': '_accent'\n\t},\n\tencapsulation: ViewEncapsulation.None\n})\nexport class HubFabComponent implements OnInit {\n\tcolor = input<HubSemanticColor>('primary');\n\tsize = input<HubFabSize>('standard');\n\textended = input(false);\n\t/** Fixed viewport position. 9-slot grid including center. */\n\tposition = input<HubFabPosition>('bottom-end');\n\t/** When true, collapses an extended FAB to icon-only on page scroll. */\n\tcollapseOnScroll = input(false);\n\tdisabled = input(false);\n\tfabClick = output<void>();\n\n\t/** Collapse state driven by scroll — only active when extended + collapseOnScroll. */\n\tprotected readonly _collapsed = signal(false);\n\n\tprivate readonly _destroyRef = inject(DestroyRef);\n\n\tprotected get _hostClass(): string {\n\t\treturn [\n\t\t\t`hub-fab-${this.color()}`,\n\t\t\t`hub-fab-${this.size()}`,\n\t\t\t`hub-fab-${this.position()}`,\n\t\t\tthis.extended() && !this._collapsed() ? 'hub-fab-extended' : '',\n\t\t\tthis.disabled() ? 'hub-fab-disabled' : ''\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' ');\n\t}\n\n\t/**\n\t * The semantic accent consumed by the base `.hub-fab` background slot\n\t * (`--hub-fab-accent`). Accepts ANY colour: a bareword (a built-in semantic\n\t * name, a host-registered accent or a CSS named colour) resolves to its\n\t * `--hub-sys-color-<name>` token with the bareword as the raw fallback, so\n\t * unregistered names still paint; a literal (`#hex`, `rgb()`, `oklch()`,\n\t * `var(...)`) is passed through unchanged. Built-in `hub-fab-<color>` classes\n\t * keep overriding the background, so this slot only paints custom / literal\n\t * colours.\n\t */\n\tprotected get _accent(): string | null {\n\t\treturn resolveHubAccent(this.color());\n\t}\n\n\tngOnInit(): void {\n\t\tif (!this.collapseOnScroll()) return;\n\n\t\tfromEvent(window, 'scroll', { passive: true })\n\t\t\t.pipe(debounceTime(50), takeUntilDestroyed(this._destroyRef))\n\t\t\t.subscribe(() => {\n\t\t\t\tthis._collapsed.set(window.scrollY > 50);\n\t\t\t});\n\t}\n}\n","<ng-content select=\"[slot=icon]\"></ng-content>\n\n@if (extended() && !_collapsed()) {\n\t<span class=\"hub-fab__label\">\n\t\t<ng-content select=\"[slot=label]\"></ng-content>\n\t</span>\n} @else if (!extended()) {\n\t<ng-content></ng-content>\n}\n","import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, DestroyRef, PLATFORM_ID, inject, input, model, output } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { fromEvent } from 'rxjs';\nimport { filter } from 'rxjs/operators';\nimport { HubFabPosition, HubFabSize, HubSemanticColor } from '../../models/button.types';\n\n/**\n * FAB that expands a stack of HubSpeedDialItemComponent children on click or hover.\n * Supports 4 expansion directions and all 9 FAB viewport positions.\n * Closes automatically on Escape key press.\n */\n@Component({\n\tselector: 'hub-speed-dial',\n\tstandalone: true,\n\ttemplateUrl: './speed-dial.component.html',\n\tstyleUrl: './speed-dial.component.scss',\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: {\n\t\tclass: 'hub-speed-dial',\n\t\t'[class]': '_hostClass'\n\t}\n})\nexport class HubSpeedDialComponent {\n\tcolor = input<HubSemanticColor>('primary');\n\tsize = input<HubFabSize>('standard');\n\tposition = input<HubFabPosition>('bottom-end');\n\tdirection = input<'up' | 'down' | 'left' | 'right'>('up');\n\ttrigger = input<'click' | 'hover'>('click');\n\tisOpen = model(false);\n\topened = output<void>();\n\tclosed = output<void>();\n\n\tprivate readonly _destroyRef = inject(DestroyRef);\n\n\tprotected get _hostClass(): string {\n\t\treturn [\n\t\t\t`hub-speed-dial-${this.color()}`,\n\t\t\t`hub-speed-dial-${this.position()}`,\n\t\t\t`hub-speed-dial-${this.direction()}`,\n\t\t\tthis.isOpen() ? 'hub-speed-dial-open' : ''\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' ');\n\t}\n\n\t/**\n\t * The semantic accent painted on the inner `.hub-fab` trigger button through its\n\t * `--hub-fab-accent` slot. Accepts ANY colour: a bareword (a built-in semantic\n\t * name, a host-registered accent or a CSS named colour) resolves to its\n\t * `--hub-sys-color-<name>` token with the bareword as the raw fallback, so\n\t * unregistered names still paint; a literal (`#hex`, `rgb()`, `oklch()`,\n\t * `var(...)`) is passed through unchanged. Built-in `hub-fab-<color>` classes on\n\t * the trigger keep overriding the background, so this slot only paints custom /\n\t * literal colours.\n\t */\n\tprotected get _accent(): string | null {\n\t\treturn resolveHubAccent(this.color());\n\t}\n\n\tconstructor() {\n\t\t// Escape-to-close relies on DOM events; inert on the server (SSR/prerender).\n\t\tif (isPlatformBrowser(inject(PLATFORM_ID))) {\n\t\t\tfromEvent<KeyboardEvent>(inject(DOCUMENT), 'keydown')\n\t\t\t\t.pipe(\n\t\t\t\t\tfilter((e) => e.key === 'Escape' && this.isOpen()),\n\t\t\t\t\ttakeUntilDestroyed(this._destroyRef)\n\t\t\t\t)\n\t\t\t\t.subscribe(() => this.close());\n\t\t}\n\t}\n\n\t/** Toggle the speed dial open/closed. */\n\ttoggle(): void {\n\t\tthis.isOpen() ? this.close() : this.open();\n\t}\n\n\t/** Open the speed dial and emit the opened event. */\n\topen(): void {\n\t\tthis.isOpen.set(true);\n\t\tthis.opened.emit();\n\t}\n\n\t/** Close the speed dial and emit the closed event. */\n\tclose(): void {\n\t\tthis.isOpen.set(false);\n\t\tthis.closed.emit();\n\t}\n}\n","<button\n\tclass=\"hub-fab\"\n\t[class]=\"'hub-fab-' + color() + ' hub-fab-' + size()\"\n\t[style.--hub-fab-accent]=\"_accent\"\n\t(click)=\"trigger() === 'click' && toggle()\"\n\t(mouseenter)=\"trigger() === 'hover' && open()\"\n\t(mouseleave)=\"trigger() === 'hover' && close()\"\n\ttype=\"button\"\n\t[attr.aria-expanded]=\"isOpen()\"\n\taria-haspopup=\"true\"\n>\n\t<ng-content select=\"[hubTrigger]\"></ng-content>\n</button>\n\n@if (isOpen()) {\n\t<div class=\"hub-speed-dial__actions\" [attr.data-direction]=\"direction()\">\n\t\t<ng-content></ng-content>\n\t</div>\n}\n","import { ChangeDetectionStrategy, Component, input, output } from '@angular/core';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { HubSemanticColor } from '../../../models/button.types';\n\n/**\n * Secondary action item rendered inside HubSpeedDialComponent.\n * Emits itemClick when activated. Supports an optional label tooltip.\n */\n@Component({\n\tselector: 'hub-speed-dial-item',\n\tstandalone: true,\n\ttemplateUrl: './speed-dial-item.component.html',\n\tstyleUrl: './speed-dial-item.component.scss',\n\tchangeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class HubSpeedDialItemComponent {\n\t/** Icon character or ligature string displayed in the action button. */\n\ticon = input.required<string>();\n\t/** Tooltip label shown next to the action button. */\n\tlabel = input('');\n\tcolor = input<HubSemanticColor | 'default'>('default');\n\tdisabled = input(false);\n\titemClick = output<void>();\n\n\t/**\n\t * The semantic accent painted on the action button through its\n\t * `--hub-speed-dial-item-accent` slot. Accepts ANY colour: a bareword (a\n\t * built-in semantic name, a host-registered accent or a CSS named colour)\n\t * resolves to its `--hub-sys-color-<name>` token with the bareword as the raw\n\t * fallback, so unregistered names still paint; a literal (`#hex`, `rgb()`,\n\t * `oklch()`, `var(...)`) is passed through unchanged. Returns `null` for the\n\t * `default` colour and for the built-in classes, which paint themselves — the\n\t * slot only takes effect for custom / literal colours.\n\t */\n\tprotected get _accent(): string | null {\n\t\treturn this.color() === 'default' ? null : resolveHubAccent(this.color());\n\t}\n}\n","@if (label()) {\n\t<span class=\"hub-speed-dial-item__label\">{{ label() }}</span>\n}\n<button\n\tclass=\"hub-speed-dial-item__btn\"\n\t[class]=\"'hub-speed-dial-item__btn--' + color()\"\n\t[style.--hub-speed-dial-item-accent]=\"_accent\"\n\t[disabled]=\"disabled() || null\"\n\t(click)=\"itemClick.emit()\"\n\ttype=\"button\"\n\t[attr.aria-label]=\"label() || icon()\"\n>\n\t<i [class]=\"icon()\" aria-hidden=\"true\"></i>\n</button>\n","import { ChangeDetectionStrategy, Component, input } from '@angular/core';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { HubSemanticColor } from '../../models/button.types';\n\n/**\n * Styled container for dropdown content.\n * Renders a shadowed panel with an optional semantic color top-border accent.\n * Place hub-dropdown-item, hub-dropdown-divider, and hub-dropdown-header children inside.\n */\n@Component({\n\tselector: 'hub-dropdown-panel',\n\tstandalone: true,\n\ttemplate: `<ng-content></ng-content>`,\n\tstyleUrl: './dropdown-panel.component.scss',\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: {\n\t\tclass: 'hub-dropdown-panel',\n\t\t'[class]': '_hostClass',\n\t\t'[style.--hub-dropdown-panel-accent]': '_accent'\n\t}\n})\nexport class HubDropdownPanelComponent {\n\t/** Adds a semantic color accent to the panel top border. */\n\tcolor = input<HubSemanticColor | 'default'>('default');\n\n\tprotected get _hostClass(): string {\n\t\treturn this.color() !== 'default' ? `hub-dropdown-panel-${this.color()}` : '';\n\t}\n\n\t/**\n\t * The semantic accent painted on the panel top border through the\n\t * `--hub-dropdown-panel-accent` slot. Accepts ANY colour: a bareword (a built-in\n\t * semantic name, a host-registered accent or a CSS named colour) resolves to its\n\t * `--hub-sys-color-<name>` token with the bareword as the raw fallback, so\n\t * unregistered names still paint; a literal (`#hex`, `rgb()`, `oklch()`,\n\t * `var(...)`) is passed through unchanged. Returns `null` for the `default`\n\t * colour (the border keeps its neutral colour) and for the built-in classes,\n\t * which paint their own thicker accent — the slot only takes effect for custom /\n\t * literal colours.\n\t */\n\tprotected get _accent(): string | null {\n\t\treturn this.color() === 'default' ? null : resolveHubAccent(this.color());\n\t}\n}\n","import { ChangeDetectionStrategy, Component, input, output } from '@angular/core';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { HubSemanticColor } from '../../models/button.types';\n\n/**\n * Menu item for use inside HubDropdownPanelComponent.\n * Emits itemClick when activated. Supports an optional icon, selected state and semantic color.\n */\n@Component({\n\tselector: 'hub-dropdown-item',\n\tstandalone: true,\n\ttemplateUrl: './dropdown-item.component.html',\n\tstyleUrl: './dropdown-item.component.scss',\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: {\n\t\tclass: 'hub-dropdown-item',\n\t\t'[class]': '_hostClass',\n\t\t'[style.--hub-dropdown-item-accent]': '_accent'\n\t}\n})\nexport class HubDropdownItemComponent {\n\tcolor = input<HubSemanticColor | 'default'>('default');\n\t/** Optional icon character or ligature displayed before the label. */\n\ticon = input<string>();\n\tdisabled = input(false);\n\t/** Shows a checkmark indicator when selected. */\n\tselected = input(false);\n\titemClick = output<void>();\n\n\tprotected get _hostClass(): string {\n\t\treturn [\n\t\t\tthis.color() !== 'default' ? `hub-dropdown-item-${this.color()}` : '',\n\t\t\tthis.disabled() ? 'hub-dropdown-item-disabled' : '',\n\t\t\tthis.selected() ? 'hub-dropdown-item-selected' : ''\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' ');\n\t}\n\n\t/**\n\t * The semantic accent painted as the item label colour through the\n\t * `--hub-dropdown-item-accent` slot. Accepts ANY colour: a bareword (a built-in\n\t * semantic name, a host-registered accent or a CSS named colour) resolves to its\n\t * `--hub-sys-color-<name>` token with the bareword as the raw fallback, so\n\t * unregistered names still paint; a literal (`#hex`, `rgb()`, `oklch()`,\n\t * `var(...)`) is passed through unchanged. Returns `null` for the `default`\n\t * colour (the item inherits its colour) and for the built-in classes, which\n\t * paint themselves — the slot only takes effect for custom / literal colours.\n\t */\n\tprotected get _accent(): string | null {\n\t\treturn this.color() === 'default' ? null : resolveHubAccent(this.color());\n\t}\n\n\tprotected _handleClick(): void {\n\t\tif (this.disabled()) return;\n\t\tthis.itemClick.emit();\n\t}\n}\n","<button class=\"hub-dropdown-item__inner\" type=\"button\" [disabled]=\"disabled() || null\" (click)=\"_handleClick()\">\n\t@if (icon()) {\n\t\t<i [class]=\"icon()\" aria-hidden=\"true\"></i>\n\t}\n\t<span class=\"hub-dropdown-item__label\"><ng-content></ng-content></span>\n\t@if (selected()) {\n\t\t<span class=\"hub-dropdown-item__check\" aria-hidden=\"true\">✓</span>\n\t}\n</button>\n","import { ChangeDetectionStrategy, Component } from '@angular/core';\n\n/** Horizontal separator for grouping items inside HubDropdownPanelComponent. */\n@Component({\n\tselector: 'hub-dropdown-divider',\n\tstandalone: true,\n\ttemplate: '',\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: {\n\t\tclass: 'hub-dropdown-divider',\n\t\trole: 'separator',\n\t\t'aria-hidden': 'true'\n\t},\n\tstyles: [\n\t\t`\n\t\t\t:host {\n\t\t\t\tdisplay: block;\n\t\t\t\theight: 1px;\n\t\t\t\tbackground: var(--hub-dropdown-divider-color, var(--hub-sys-color-border-subtle, #dee2e6));\n\t\t\t\tmargin: var(--hub-ref-space-1, 0.25rem) 0;\n\t\t\t}\n\t\t`\n\t]\n})\nexport class HubDropdownDividerComponent {}\n","import { ChangeDetectionStrategy, Component } from '@angular/core';\n\n/** Group label for organizing items inside HubDropdownPanelComponent. */\n@Component({\n\tselector: 'hub-dropdown-header',\n\tstandalone: true,\n\ttemplate: `<ng-content></ng-content>`,\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: { class: 'hub-dropdown-header' },\n\tstyles: [\n\t\t`\n\t\t\t:host {\n\t\t\t\tdisplay: block;\n\t\t\t\tpadding: 0.375rem var(--hub-dropdown-header-padding-x, var(--hub-ref-space-3, 1rem)) 0.1875rem;\n\t\t\t\tfont-size: var(--hub-dropdown-header-font-size, var(--hub-ref-font-size-xs, 0.75rem));\n\t\t\t\tfont-weight: var(--hub-ref-font-weight-bold, 700);\n\t\t\t\tcolor: var(--hub-dropdown-header-color, var(--hub-sys-color-text-subtle, #6c757d));\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tletter-spacing: 0.06em;\n\t\t\t}\n\t\t`\n\t]\n})\nexport class HubDropdownHeaderComponent {}\n","import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport {\n\tDestroyRef,\n\tDirective,\n\tElementRef,\n\tPLATFORM_ID,\n\tTemplateRef,\n\tViewContainerRef,\n\tinject,\n\tinput,\n\tmodel,\n\toutput,\n\tsignal\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { fromEvent } from 'rxjs';\nimport { filter, take } from 'rxjs/operators';\nimport { OverlayService } from 'ng-hub-ui-utils';\nimport type { OverlayRef, ConnectionPosition } from 'ng-hub-ui-utils';\nimport { HubDropdownPlacement } from '../models/button.types';\n\n/**\n * The one dropdown currently open, anywhere on the page.\n *\n * Closing on click-outside already made a second one *usually* replace the first, since\n * opening it is itself a click outside the first. Usually is not a guarantee: a dropdown\n * opened from code — a keyboard shortcut, a menu restored after a re-render, a table row\n * that opens its own — produces no such click, and two panels stay up at once. Held in a\n * module variable rather than a service because the rule is about the page, not about\n * anything injectable, and a service would make every consumer provide one to get it.\n */\nlet openDropdown: HubDropdownDirective | null = null;\n\n/**\n * Turns any host element into a dropdown trigger.\n * Renders an ng-template in a body-level overlay managed by OverlayService (no CDK).\n * When closeOnSelect is true, any click inside the panel closes the overlay automatically.\n *\n * Only one dropdown is open at a time: opening one closes whichever was already open,\n * however it was opened.\n */\n@Directive({\n\tselector: '[hubDropdown]',\n\tstandalone: true,\n\texportAs: 'hubDropdown',\n\thost: {\n\t\t'(click)': '_onHostClick()',\n\t\t'(mouseenter)': '_onHostEnter()',\n\t\t'(mouseleave)': '_onHostLeave()'\n\t}\n})\nexport class HubDropdownDirective {\n\t/** The ng-template to render inside the overlay panel. */\n\ttpl = input.required<TemplateRef<any>>({ alias: 'hubDropdown' });\n\tplacement = input<HubDropdownPlacement>('bottom-start');\n\ttrigger = input<'click' | 'hover'>('click');\n\t/** When true, any click inside the panel content closes the dropdown. */\n\tcloseOnSelect = input(true);\n\tdisabled = input(false);\n\t/** Vertical offset in pixels between the trigger and the panel. */\n\toffsetY = input(4);\n\tpanelClass = input('');\n\tisOpen = model(false);\n\topened = output<void>();\n\tclosed = output<void>();\n\n\tprivate _overlayRef: OverlayRef | null = null;\n\n\tprivate readonly _el = inject(ElementRef<HTMLElement>);\n\tprivate readonly _vcr = inject(ViewContainerRef);\n\tprivate readonly _overlay = inject(OverlayService);\n\tprivate readonly _destroyRef = inject(DestroyRef);\n\tprivate readonly _document = inject(DOCUMENT);\n\n\tconstructor() {\n\t\t// Escape-to-close relies on DOM events; inert on the server (SSR/prerender).\n\t\tif (isPlatformBrowser(inject(PLATFORM_ID))) {\n\t\t\tfromEvent<KeyboardEvent>(this._document, 'keydown')\n\t\t\t\t.pipe(\n\t\t\t\t\tfilter((e) => e.key === 'Escape' && this.isOpen()),\n\t\t\t\t\ttakeUntilDestroyed(this._destroyRef)\n\t\t\t\t)\n\t\t\t\t.subscribe(() => this.close());\n\t\t}\n\n\t\t// Torn down silently, not closed. `close()` emits `closed`, and a component that\n\t\t// is already gone has nobody to tell — Angular reports that as NG0953. Two things\n\t\t// have to go: the overlay, which lives on the body and would otherwise outlive the\n\t\t// view that owns it, and this directive's place as the one open dropdown, which\n\t\t// would leave a destroyed instance to be closed by whoever opens the next one.\n\t\tthis._destroyRef.onDestroy(() => {\n\t\t\tif (openDropdown === this) {\n\t\t\t\topenDropdown = null;\n\t\t\t}\n\n\t\t\tthis._overlayRef?.detach();\n\t\t\tthis._overlayRef?.dispose();\n\t\t\tthis._overlayRef = null;\n\t\t});\n\t}\n\n\t/** Open the dropdown and mount the overlay, closing whichever one was open. */\n\topen(): void {\n\t\tif (this.disabled() || this.isOpen()) return;\n\n\t\topenDropdown?.close();\n\t\topenDropdown = this;\n\n\t\tconst positionStrategy = this._overlay.position().flexibleConnectedTo(this._el).withPositions(this._buildPositions());\n\n\t\tconst panelClasses = ['hub-dropdown-overlay'];\n\t\tif (this.panelClass()) panelClasses.push(this.panelClass());\n\n\t\tthis._overlayRef = this._overlay.create({ positionStrategy, panelClass: panelClasses });\n\n\t\tconst panelEl = this._overlayRef.attach(this.tpl(), this._vcr);\n\n\t\t// Close on click-outside via backdrop\n\t\tthis._overlayRef.onBackdropClick(() => this.close());\n\n\t\t// Close on click-inside when closeOnSelect is true\n\t\tif (this.closeOnSelect() && panelEl) {\n\t\t\tfromEvent<MouseEvent>(panelEl, 'click')\n\t\t\t\t.pipe(take(1), takeUntilDestroyed(this._destroyRef))\n\t\t\t\t.subscribe(() => this.close());\n\t\t}\n\n\t\tthis.isOpen.set(true);\n\t\tthis.opened.emit();\n\n\t\t// Close on scroll so the panel stays aligned with the trigger\n\t\tfromEvent(this._document, 'scroll', { passive: true, capture: true })\n\t\t\t.pipe(take(1), takeUntilDestroyed(this._destroyRef))\n\t\t\t.subscribe(() => this.close());\n\n\t\t// Click-outside detection (document-level)\n\t\tfromEvent<MouseEvent>(this._document, 'click')\n\t\t\t.pipe(\n\t\t\t\tfilter((e) => !this._el.nativeElement.contains(e.target as Node) && !!this._overlayRef?.hasAttached()),\n\t\t\t\ttake(1),\n\t\t\t\ttakeUntilDestroyed(this._destroyRef)\n\t\t\t)\n\t\t\t.subscribe(() => this.close());\n\t}\n\n\t/** Close the dropdown and destroy the overlay. */\n\tclose(): void {\n\t\tif (!this.isOpen()) return;\n\t\tif (openDropdown === this) {\n\t\t\t// Cleared before the overlay goes, so a listener that closes on the way out\n\t\t\t// cannot find this one still recorded as the open one.\n\t\t\topenDropdown = null;\n\t\t}\n\t\tthis._overlayRef?.detach();\n\t\tthis._overlayRef?.dispose();\n\t\tthis._overlayRef = null;\n\t\tthis.isOpen.set(false);\n\t\tthis.closed.emit();\n\t}\n\n\t/** Toggle between open and closed. */\n\ttoggle(): void {\n\t\tthis.isOpen() ? this.close() : this.open();\n\t}\n\n\tprotected _onHostClick(): void {\n\t\tif (this.trigger() === 'click') this.toggle();\n\t}\n\n\tprotected _onHostEnter(): void {\n\t\tif (this.trigger() === 'hover') this.open();\n\t}\n\n\tprotected _onHostLeave(): void {\n\t\tif (this.trigger() === 'hover') this.close();\n\t}\n\n\t/**\n\t * Translates HubDropdownPlacement tokens to ConnectionPosition arrays.\n\t * The OverlayPosition tries each entry in order, using the first that fits.\n\t */\n\tprivate _buildPositions(): ConnectionPosition[] {\n\t\tconst o = this.offsetY();\n\t\tconst map: Record<HubDropdownPlacement, ConnectionPosition[]> = {\n\t\t\t'bottom-start': [{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: o }],\n\t\t\tbottom: [{ originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: o }],\n\t\t\t'bottom-end': [{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: o }],\n\t\t\t'top-start': [{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -o }],\n\t\t\ttop: [{ originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -o }],\n\t\t\t'top-end': [{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -o }],\n\t\t\tstart: [{ originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center', offsetX: -o }],\n\t\t\tend: [{ originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center', offsetX: o }]\n\t\t};\n\t\treturn map[this.placement()];\n\t}\n}\n","/**\n * Framework-neutral description of one table row's actions.\n *\n * The shape mirrors (structurally) the contract other ng-hub-ui libraries expose for\n * optional action hosting — `ng-hub-ui-paginable`'s `HubPaginableActionsAdapter` — so\n * this adapter can be wired into them without either package importing the other. It is\n * the same arrangement `hubFormControlAdapter` already uses for the table's inputs.\n *\n * Everything here is already resolved for the row: no predicates, no streams. A host\n * library that lets consumers write those resolves them before describing the cell.\n */\n\n/** Where a menu panel opens relative to its trigger. */\nexport type HubRowMenuPlacement = 'top-start' | 'top' | 'top-end' | 'start' | 'end' | 'bottom-start' | 'bottom' | 'bottom-end';\n\n/** One thing a person can do to a row. */\nexport interface HubRowActionItem {\n\ticon?: string;\n\tlabel?: string;\n\ttooltip?: string;\n\tvariant?: string;\n\tcolor?: string;\n\t/** Drawn and refused — not absent. An absence cannot say «not right now». */\n\tdisabled: boolean;\n\tonSelect: () => void;\n}\n\nexport interface HubRowButtonAction extends HubRowActionItem {\n\tkind: 'button';\n}\n\nexport interface HubRowMenuAction extends Omit<HubRowActionItem, 'onSelect'> {\n\tkind: 'menu';\n\tplacement?: HubRowMenuPlacement;\n\titems: ReadonlyArray<HubRowActionItem>;\n}\n\nexport type HubRowAction = HubRowButtonAction | HubRowMenuAction;\n\nexport interface HubActionsCellConfig {\n\tactions: ReadonlyArray<HubRowAction>;\n}\n\n/** Live handle to the actions created by {@link hubActionsAdapter}. */\nexport interface HubActionsHandle {\n\tupdate(config: HubActionsCellConfig): void;\n\tdestroy(): void;\n}\n\n/** What a host library injects to have its row actions drawn by this library. */\nexport interface HubActionsAdapter {\n\tcreate(container: unknown, config: HubActionsCellConfig): HubActionsHandle;\n}\n","import { NgClass } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, input } from '@angular/core';\nimport { HubButtonComponent } from '../components/btn/button.component';\nimport { HubDropdownItemComponent } from '../components/dropdown-item/dropdown-item.component';\nimport { HubDropdownPanelComponent } from '../components/dropdown-panel/dropdown-panel.component';\nimport { HubDropdownDirective } from '../directives/dropdown.directive';\nimport { HubBtnVariant } from '../models/button.types';\nimport { HubActionsCellConfig, HubRowAction, HubRowMenuAction } from './actions.types';\n\n/** The appearances this library draws; anything else falls back to `soft`. */\nconst KNOWN_VARIANTS: ReadonlyArray<HubBtnVariant> = ['solid', 'outline', 'soft', 'ghost', 'link'];\n\n/**\n * One table row's actions, drawn with the design system's own button and dropdown.\n *\n * Exists so the adapter can create a single component instead of assembling a directive,\n * a template reference and a panel by hand: `hubDropdown` needs a host element and an\n * `ng-template`, which is natural in a template and awkward imperatively.\n *\n * It knows nothing about tables. Its input is the neutral description a host library\n * hands over, which is what keeps `ng-hub-ui-buttons` free of any dependency on the\n * library that renders it.\n */\n@Component({\n\tselector: 'hub-actions-cell',\n\tstandalone: true,\n\timports: [NgClass, HubButtonComponent, HubDropdownDirective, HubDropdownPanelComponent, HubDropdownItemComponent],\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\ttemplate: `\n\t\t@for (action of config().actions; track $index) {\n\t\t\t@if (asMenu(action); as menu) {\n\t\t\t\t<button\n\t\t\t\t\thubButton\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t[variant]=\"asVariant(menu.variant)\"\n\t\t\t\t\t[color]=\"menu.color ?? 'neutral'\"\n\t\t\t\t\t[disabled]=\"menu.disabled\"\n\t\t\t\t\t[attr.title]=\"menu.tooltip ?? null\"\n\t\t\t\t\t[attr.aria-label]=\"menu.tooltip ?? menu.label ?? null\"\n\t\t\t\t\t[hubDropdown]=\"panel\"\n\t\t\t\t\t[placement]=\"menu.placement ?? 'bottom-end'\"\n\t\t\t\t\t(click)=\"$event.stopPropagation()\"\n\t\t\t\t>\n\t\t\t\t\t@if (menu.icon) {\n\t\t\t\t\t\t<i [ngClass]=\"menu.icon\" aria-hidden=\"true\"></i>\n\t\t\t\t\t}\n\t\t\t\t\t@if (menu.label) {\n\t\t\t\t\t\t<span>{{ menu.label }}</span>\n\t\t\t\t\t}\n\t\t\t\t</button>\n\n\t\t\t\t<ng-template #panel>\n\t\t\t\t\t<hub-dropdown-panel>\n\t\t\t\t\t\t@for (item of menu.items; track $index) {\n\t\t\t\t\t\t\t<hub-dropdown-item [icon]=\"item.icon\" [disabled]=\"item.disabled\" (itemClick)=\"item.onSelect()\">\n\t\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t\t</hub-dropdown-item>\n\t\t\t\t\t\t}\n\t\t\t\t\t</hub-dropdown-panel>\n\t\t\t\t</ng-template>\n\t\t\t} @else {\n\t\t\t\t<button\n\t\t\t\t\thubButton\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t[variant]=\"asVariant(action.variant)\"\n\t\t\t\t\t[color]=\"action.color ?? 'neutral'\"\n\t\t\t\t\t[disabled]=\"action.disabled\"\n\t\t\t\t\t[attr.title]=\"action.tooltip ?? null\"\n\t\t\t\t\t[attr.aria-label]=\"action.tooltip ?? action.label ?? null\"\n\t\t\t\t\t(click)=\"onSelect(action, $event)\"\n\t\t\t\t>\n\t\t\t\t\t@if (action.icon) {\n\t\t\t\t\t\t<i [ngClass]=\"action.icon\" aria-hidden=\"true\"></i>\n\t\t\t\t\t}\n\t\t\t\t\t@if (action.label) {\n\t\t\t\t\t\t<span>{{ action.label }}</span>\n\t\t\t\t\t}\n\t\t\t\t</button>\n\t\t\t}\n\t\t}\n\t`,\n\thost: {\n\t\tclass: 'hub-actions-cell',\n\t\tstyle: 'display: inline-flex; align-items: center; gap: var(--hub-ref-space-2, 0.5rem);'\n\t}\n})\nexport class HubActionsCellComponent {\n\treadonly config = input.required<HubActionsCellConfig>();\n\n\t/**\n\t * Narrows an action to a menu, for the template's `@if (…; as menu)`.\n\t *\n\t * A type guard rather than a `kind` comparison in the template, because the template\n\t * cannot narrow a union on its own and would otherwise need a cast at every field.\n\t */\n\tprotected asMenu(action: HubRowAction): HubRowMenuAction | null {\n\t\treturn action.kind === 'menu' ? action : null;\n\t}\n\n\t/**\n\t * Narrows the host's open vocabulary onto this library's closed one.\n\t *\n\t * A host names appearances in its own terms and leaves the type open — the table, for\n\t * one, has a `default` that means «the plain bordered button I have always drawn», a\n\t * name this library does not have. Anything unrecognised becomes `soft`, which is what\n\t * a row action looks like here, rather than a type error in code that works.\n\t */\n\tprotected asVariant(variant: string | undefined): HubBtnVariant {\n\t\treturn KNOWN_VARIANTS.includes(variant as HubBtnVariant) ? (variant as HubBtnVariant) : 'soft';\n\t}\n\n\t/**\n\t * Runs the action and keeps the click from reaching the row underneath.\n\t *\n\t * A host that draws these inside clickable rows — a table whose rows open a detail\n\t * page — would otherwise navigate away every time somebody pressed a row action, and\n\t * the action's own effect would be lost with the screen it happened on. A click on an\n\t * action is never a click on what surrounds it, whoever surrounds it.\n\t */\n\tprotected onSelect(action: HubRowAction, event: Event): void {\n\t\tevent.stopPropagation();\n\n\t\tif (action.kind === 'menu' || action.disabled) {\n\t\t\treturn;\n\t\t}\n\t\taction.onSelect();\n\t}\n}\n","import { ViewContainerRef } from '@angular/core';\nimport { HubActionsCellComponent } from './actions-cell.component';\nimport { HubActionsAdapter, HubActionsCellConfig, HubActionsHandle } from './actions.types';\n\n/**\n * Draws a host library's row actions with this library's button and dropdown.\n *\n * Register it where the host expects it — for `ng-hub-ui-paginable`:\n *\n * ```ts\n * import { provideHubPaginableActions } from 'ng-hub-ui-paginable';\n * import { hubActionsAdapter } from 'ng-hub-ui-buttons';\n *\n * providers: [provideHubPaginableActions(hubActionsAdapter)];\n * ```\n *\n * The host describes each row's actions in neutral terms and this maps them onto the\n * real components, so neither package imports the other and the application is the only\n * place that knows both exist.\n */\nexport const hubActionsAdapter: HubActionsAdapter = {\n\tcreate(container: unknown, config: HubActionsCellConfig): HubActionsHandle {\n\t\tconst ref = (container as ViewContainerRef).createComponent(HubActionsCellComponent);\n\t\tref.setInput('config', config);\n\n\t\treturn {\n\t\t\tupdate(next: HubActionsCellConfig): void {\n\t\t\t\t// A new object every time, so `input.required` sees a change: the host\n\t\t\t\t// rebuilds the description on each row change and mutating in place would\n\t\t\t\t// leave an OnPush cell showing the previous row's actions.\n\t\t\t\tref.setInput('config', { ...next });\n\t\t\t\tref.changeDetectorRef.markForCheck();\n\t\t\t},\n\t\t\tdestroy(): void {\n\t\t\t\tref.destroy();\n\t\t\t}\n\t\t};\n\t}\n};\n","/*\n * Public API Surface of ng-hub-ui-buttons\n */\n\n// Types\nexport * from './lib/models/button.types';\n\n// Tokens\nexport * from './lib/tokens/dropdown.token';\n\n// Components\nexport * from './lib/components/btn/button.component';\n/**\n * @deprecated Renamed to `HubButtonComponent`. The component now also matches the\n * `[hubButton]` attribute selector, so it replaces the former `HubBtnDirective`.\n */\nexport { HubButtonComponent as HubBtnComponent } from './lib/components/btn/button.component';\n/**\n * @deprecated Replaced by `HubButtonComponent`, which now matches `[hubButton]` itself\n * (and renders the loading spinner in the attribute form too).\n */\nexport { HubButtonComponent as HubBtnDirective } from './lib/components/btn/button.component';\nexport * from './lib/components/fab/fab.component';\nexport * from './lib/components/speed-dial/speed-dial.component';\nexport * from './lib/components/speed-dial/speed-dial-item/speed-dial-item.component';\nexport * from './lib/components/dropdown-panel/dropdown-panel.component';\nexport * from './lib/components/dropdown-item/dropdown-item.component';\nexport * from './lib/components/dropdown-divider/dropdown-divider.component';\nexport * from './lib/components/dropdown-header/dropdown-header.component';\n\n// Directives\nexport * from './lib/directives/dropdown.directive';\n\n// Cross-library integrations\nexport * from './lib/integrations/actions.types';\nexport * from './lib/integrations/actions-cell.component';\nexport * from './lib/integrations/actions-adapter';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;AAcA;MACa,gBAAgB,GAAG,IAAI,cAAc,CAAkB,oBAAoB;;ACXxF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BG;MAmBU,kBAAkB,CAAA;AAC9B;;;;;AAKG;IACc,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC,OAAO,KAAK,YAAY;;IAG3F,OAAO,GAAG,KAAK,CAAgB,OAAO;gFAAC;;IAGvC,KAAK,GAAG,KAAK,CAAmB,SAAS;8EAAC;;IAG1C,IAAI,GAAG,KAAK,CAAa,IAAI;6EAAC;AAE9B;;;;;AAKG;IACH,OAAO,GAAG,KAAK,CAAC,KAAK,+EAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AAEvD;;;;;;AAMG;IACH,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AAExD;;;;;AAKG;AACH,IAAA,IAAY,QAAQ,GAAA;QACnB,OAAO,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE;IACzC;;AAGA,IAAA,IAAc,UAAU,GAAA;QACvB,OAAO;AACN,YAAA,CAAA,QAAA,EAAW,IAAI,CAAC,OAAO,EAAE,CAAA,CAAE;AAC3B,YAAA,CAAA,QAAA,EAAW,IAAI,CAAC,KAAK,EAAE,CAAA,CAAE;AACzB,YAAA,CAAA,QAAA,EAAW,IAAI,CAAC,IAAI,EAAE,CAAA,CAAE;YACxB,IAAI,CAAC,OAAO,EAAE,GAAG,iBAAiB,GAAG,EAAE;YACvC,IAAI,CAAC,QAAQ,EAAE,GAAG,kBAAkB,GAAG;AACvC;aACC,MAAM,CAAC,OAAO;aACd,IAAI,CAAC,GAAG,CAAC;IACZ;AAEA;;;;;;;;;AASG;AACH,IAAA,IAAc,OAAO,GAAA;AACpB,QAAA,OAAO,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACtC;;AAGA,IAAA,IAAc,aAAa,GAAA;QAC1B,OAAO,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI;IACnC;;AAGA,IAAA,IAAc,SAAS,GAAA;AACtB,QAAA,OAAO,IAAI,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,IAAI;IACtC;AAEA;;;;AAIG;AACH,IAAA,IAAc,aAAa,GAAA;AAC1B,QAAA,OAAO,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,QAAQ,GAAG,MAAM,GAAG,IAAI;IAC5D;AAEA;;;AAGG;AACH,IAAA,IAAc,KAAK,GAAA;QAClB,OAAO,IAAI,CAAC,cAAc,GAAG,QAAQ,GAAG,IAAI;IAC7C;AAEA;;;AAGG;AACH,IAAA,IAAc,SAAS,GAAA;AACtB,QAAA,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;AACzB,YAAA,OAAO,IAAI;QACZ;AAEA,QAAA,OAAO,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC;IAC9B;AAEA;;;;;;AAMG;AACO,IAAA,UAAU,CAAC,KAAoB,EAAA;QACxC,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,QAAQ,EAAE;YAC1C;QACD;AAEA,QAAA,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,KAAK,UAAU;QAE7D,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,OAAO,EAAE;YACrC,IAAI,OAAO,EAAE;gBACZ,KAAK,CAAC,cAAc,EAAE;YACvB;AAEC,YAAA,KAAK,CAAC,aAA6B,CAAC,KAAK,EAAE;QAC7C;IACD;uGApIY,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAlB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,kBAAkB,sgCCpD/B,oHAIA,EAAA,MAAA,EAAA,CAAA,6/OAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDgDa,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAlB9B,SAAS;AACC,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,yBAAyB,cACvB,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACL,wBAAA,KAAK,EAAE,SAAS;AAChB,wBAAA,SAAS,EAAE,YAAY;AACvB,wBAAA,0BAA0B,EAAE,SAAS;AACrC,wBAAA,iBAAiB,EAAE,eAAe;AAClC,wBAAA,kBAAkB,EAAE,WAAW;AAC/B,wBAAA,sBAAsB,EAAE,eAAe;AACvC,wBAAA,aAAa,EAAE,OAAO;AACtB,wBAAA,iBAAiB,EAAE,WAAW;AAC9B,wBAAA,WAAW,EAAE;AACb,qBAAA,EAAA,QAAA,EAAA,oHAAA,EAAA,MAAA,EAAA,CAAA,6/OAAA,CAAA,EAAA;;;AEjCF;;;;;AAKG;MAcU,eAAe,CAAA;IAC3B,KAAK,GAAG,KAAK,CAAmB,SAAS;8EAAC;IAC1C,IAAI,GAAG,KAAK,CAAa,UAAU;6EAAC;IACpC,QAAQ,GAAG,KAAK,CAAC,KAAK;iFAAC;;IAEvB,QAAQ,GAAG,KAAK,CAAiB,YAAY;iFAAC;;IAE9C,gBAAgB,GAAG,KAAK,CAAC,KAAK;yFAAC;IAC/B,QAAQ,GAAG,KAAK,CAAC,KAAK;iFAAC;IACvB,QAAQ,GAAG,MAAM,EAAQ;;IAGN,UAAU,GAAG,MAAM,CAAC,KAAK;mFAAC;AAE5B,IAAA,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC;AAEjD,IAAA,IAAc,UAAU,GAAA;QACvB,OAAO;AACN,YAAA,CAAA,QAAA,EAAW,IAAI,CAAC,KAAK,EAAE,CAAA,CAAE;AACzB,YAAA,CAAA,QAAA,EAAW,IAAI,CAAC,IAAI,EAAE,CAAA,CAAE;AACxB,YAAA,CAAA,QAAA,EAAW,IAAI,CAAC,QAAQ,EAAE,CAAA,CAAE;AAC5B,YAAA,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,kBAAkB,GAAG,EAAE;YAC/D,IAAI,CAAC,QAAQ,EAAE,GAAG,kBAAkB,GAAG;AACvC;aACC,MAAM,CAAC,OAAO;aACd,IAAI,CAAC,GAAG,CAAC;IACZ;AAEA;;;;;;;;;AASG;AACH,IAAA,IAAc,OAAO,GAAA;AACpB,QAAA,OAAO,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACtC;IAEA,QAAQ,GAAA;AACP,QAAA,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE;YAAE;QAE9B,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;AAC3C,aAAA,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;aAC3D,SAAS,CAAC,MAAK;YACf,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,GAAG,EAAE,CAAC;AACzC,QAAA,CAAC,CAAC;IACJ;uGAlDY,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAf,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,eAAe,4+BCpC5B,4PASA,EAAA,MAAA,EAAA,CAAA,07GAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FD2Ba,eAAe,EAAA,UAAA,EAAA,CAAA;kBAb3B,SAAS;AACC,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,SAAS,cACP,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACL,wBAAA,KAAK,EAAE,SAAS;AAChB,wBAAA,SAAS,EAAE,YAAY;AACvB,wBAAA,0BAA0B,EAAE;qBAC5B,EAAA,aAAA,EACc,iBAAiB,CAAC,IAAI,EAAA,QAAA,EAAA,4PAAA,EAAA,MAAA,EAAA,CAAA,07GAAA,CAAA,EAAA;;;AE1BtC;;;;AAIG;MAYU,qBAAqB,CAAA;IACjC,KAAK,GAAG,KAAK,CAAmB,SAAS;8EAAC;IAC1C,IAAI,GAAG,KAAK,CAAa,UAAU;6EAAC;IACpC,QAAQ,GAAG,KAAK,CAAiB,YAAY;iFAAC;IAC9C,SAAS,GAAG,KAAK,CAAmC,IAAI;kFAAC;IACzD,OAAO,GAAG,KAAK,CAAoB,OAAO;gFAAC;IAC3C,MAAM,GAAG,KAAK,CAAC,KAAK;+EAAC;IACrB,MAAM,GAAG,MAAM,EAAQ;IACvB,MAAM,GAAG,MAAM,EAAQ;AAEN,IAAA,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC;AAEjD,IAAA,IAAc,UAAU,GAAA;QACvB,OAAO;AACN,YAAA,CAAA,eAAA,EAAkB,IAAI,CAAC,KAAK,EAAE,CAAA,CAAE;AAChC,YAAA,CAAA,eAAA,EAAkB,IAAI,CAAC,QAAQ,EAAE,CAAA,CAAE;AACnC,YAAA,CAAA,eAAA,EAAkB,IAAI,CAAC,SAAS,EAAE,CAAA,CAAE;YACpC,IAAI,CAAC,MAAM,EAAE,GAAG,qBAAqB,GAAG;AACxC;aACC,MAAM,CAAC,OAAO;aACd,IAAI,CAAC,GAAG,CAAC;IACZ;AAEA;;;;;;;;;AASG;AACH,IAAA,IAAc,OAAO,GAAA;AACpB,QAAA,OAAO,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACtC;AAEA,IAAA,WAAA,GAAA;;QAEC,IAAI,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE;AAC3C,YAAA,SAAS,CAAgB,MAAM,CAAC,QAAQ,CAAC,EAAE,SAAS;iBAClD,IAAI,CACJ,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,EAClD,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;iBAEpC,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QAChC;IACD;;IAGA,MAAM,GAAA;AACL,QAAA,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE;IAC3C;;IAGA,IAAI,GAAA;AACH,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;AACrB,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;IACnB;;IAGA,KAAK,GAAA;AACJ,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;IACnB;uGAhEY,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAArB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,qBAAqB,69BCxBlC,mkBAmBA,EAAA,MAAA,EAAA,CAAA,w2CAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDKa,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBAXjC,SAAS;AACC,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gBAAgB,cACd,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACL,wBAAA,KAAK,EAAE,gBAAgB;AACvB,wBAAA,SAAS,EAAE;AACX,qBAAA,EAAA,QAAA,EAAA,mkBAAA,EAAA,MAAA,EAAA,CAAA,w2CAAA,CAAA,EAAA;;;AElBF;;;AAGG;MAQU,yBAAyB,CAAA;;IAErC,IAAI,GAAG,KAAK,CAAC,QAAQ;6EAAU;;IAE/B,KAAK,GAAG,KAAK,CAAC,EAAE;8EAAC;IACjB,KAAK,GAAG,KAAK,CAA+B,SAAS;8EAAC;IACtD,QAAQ,GAAG,KAAK,CAAC,KAAK;iFAAC;IACvB,SAAS,GAAG,MAAM,EAAQ;AAE1B;;;;;;;;;AASG;AACH,IAAA,IAAc,OAAO,GAAA;QACpB,OAAO,IAAI,CAAC,KAAK,EAAE,KAAK,SAAS,GAAG,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1E;uGArBY,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAzB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,yBAAyB,qmBCftC,sbAcA,EAAA,MAAA,EAAA,CAAA,u9DAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDCa,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBAPrC,SAAS;AACC,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,qBAAqB,EAAA,UAAA,EACnB,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,sbAAA,EAAA,MAAA,EAAA,CAAA,u9DAAA,CAAA,EAAA;;;AEThD;;;;AAIG;MAaU,yBAAyB,CAAA;;IAErC,KAAK,GAAG,KAAK,CAA+B,SAAS;8EAAC;AAEtD,IAAA,IAAc,UAAU,GAAA;AACvB,QAAA,OAAO,IAAI,CAAC,KAAK,EAAE,KAAK,SAAS,GAAG,sBAAsB,IAAI,CAAC,KAAK,EAAE,CAAA,CAAE,GAAG,EAAE;IAC9E;AAEA;;;;;;;;;;AAUG;AACH,IAAA,IAAc,OAAO,GAAA;QACpB,OAAO,IAAI,CAAC,KAAK,EAAE,KAAK,SAAS,GAAG,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1E;uGArBY,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAzB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,yBAAyB,yVAT3B,CAAA,yBAAA,CAA2B,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,wwDAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FASzB,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBAZrC,SAAS;+BACC,oBAAoB,EAAA,UAAA,EAClB,IAAI,EAAA,QAAA,EACN,CAAA,yBAAA,CAA2B,mBAEpB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACL,wBAAA,KAAK,EAAE,oBAAoB;AAC3B,wBAAA,SAAS,EAAE,YAAY;AACvB,wBAAA,qCAAqC,EAAE;AACvC,qBAAA,EAAA,MAAA,EAAA,CAAA,wwDAAA,CAAA,EAAA;;;ACfF;;;AAGG;MAaU,wBAAwB,CAAA;IACpC,KAAK,GAAG,KAAK,CAA+B,SAAS;8EAAC;;AAEtD,IAAA,IAAI,GAAG,KAAK;wFAAU;IACtB,QAAQ,GAAG,KAAK,CAAC,KAAK;iFAAC;;IAEvB,QAAQ,GAAG,KAAK,CAAC,KAAK;iFAAC;IACvB,SAAS,GAAG,MAAM,EAAQ;AAE1B,IAAA,IAAc,UAAU,GAAA;QACvB,OAAO;AACN,YAAA,IAAI,CAAC,KAAK,EAAE,KAAK,SAAS,GAAG,CAAA,kBAAA,EAAqB,IAAI,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE;YACrE,IAAI,CAAC,QAAQ,EAAE,GAAG,4BAA4B,GAAG,EAAE;YACnD,IAAI,CAAC,QAAQ,EAAE,GAAG,4BAA4B,GAAG;AACjD;aACC,MAAM,CAAC,OAAO;aACd,IAAI,CAAC,GAAG,CAAC;IACZ;AAEA;;;;;;;;;AASG;AACH,IAAA,IAAc,OAAO,GAAA;QACpB,OAAO,IAAI,CAAC,KAAK,EAAE,KAAK,SAAS,GAAG,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1E;IAEU,YAAY,GAAA;QACrB,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AACrB,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;IACtB;uGApCY,wBAAwB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAxB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,wBAAwB,kvBCpBrC,4YASA,EAAA,MAAA,EAAA,CAAA,65EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDWa,wBAAwB,EAAA,UAAA,EAAA,CAAA;kBAZpC,SAAS;AACC,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,mBAAmB,cACjB,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACL,wBAAA,KAAK,EAAE,mBAAmB;AAC1B,wBAAA,SAAS,EAAE,YAAY;AACvB,wBAAA,oCAAoC,EAAE;AACtC,qBAAA,EAAA,QAAA,EAAA,4YAAA,EAAA,MAAA,EAAA,CAAA,65EAAA,CAAA,EAAA;;;AEhBF;MAsBa,2BAA2B,CAAA;uGAA3B,2BAA2B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA3B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,2BAA2B,8LAlB7B,EAAE,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,qKAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAkBA,2BAA2B,EAAA,UAAA,EAAA,CAAA;kBArBvC,SAAS;+BACC,sBAAsB,EAAA,UAAA,EACpB,IAAI,EAAA,QAAA,EACN,EAAE,mBACK,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACL,wBAAA,KAAK,EAAE,sBAAsB;AAC7B,wBAAA,IAAI,EAAE,WAAW;AACjB,wBAAA,aAAa,EAAE;AACf,qBAAA,EAAA,MAAA,EAAA,CAAA,qKAAA,CAAA,EAAA;;;ACVF;MAqBa,0BAA0B,CAAA;uGAA1B,0BAA0B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA1B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,0BAA0B,gIAjB5B,CAAA,yBAAA,CAA2B,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,yXAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAiBzB,0BAA0B,EAAA,UAAA,EAAA,CAAA;kBApBtC,SAAS;AACC,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,qBAAqB,EAAA,UAAA,EACnB,IAAI,EAAA,QAAA,EACN,CAAA,yBAAA,CAA2B,EAAA,eAAA,EACpB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC,EAAE,KAAK,EAAE,qBAAqB,EAAE,EAAA,MAAA,EAAA,CAAA,yXAAA,CAAA,EAAA;;;ACavC;;;;;;;;;AASG;AACH,IAAI,YAAY,GAAgC,IAAI;AAEpD;;;;;;;AAOG;MAWU,oBAAoB,CAAA;;IAEhC,GAAG,GAAG,KAAK,CAAC,QAAQ,0EAAqB,KAAK,EAAE,aAAa,EAAA,CAAG;IAChE,SAAS,GAAG,KAAK,CAAuB,cAAc;kFAAC;IACvD,OAAO,GAAG,KAAK,CAAoB,OAAO;gFAAC;;IAE3C,aAAa,GAAG,KAAK,CAAC,IAAI;sFAAC;IAC3B,QAAQ,GAAG,KAAK,CAAC,KAAK;iFAAC;;IAEvB,OAAO,GAAG,KAAK,CAAC,CAAC;gFAAC;IAClB,UAAU,GAAG,KAAK,CAAC,EAAE;mFAAC;IACtB,MAAM,GAAG,KAAK,CAAC,KAAK;+EAAC;IACrB,MAAM,GAAG,MAAM,EAAQ;IACvB,MAAM,GAAG,MAAM,EAAQ;IAEf,WAAW,GAAsB,IAAI;AAE5B,IAAA,GAAG,GAAG,MAAM,EAAC,UAAuB,EAAC;AACrC,IAAA,IAAI,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAC/B,IAAA,QAAQ,GAAG,MAAM,CAAC,cAAc,CAAC;AACjC,IAAA,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC;AAChC,IAAA,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC;AAE7C,IAAA,WAAA,GAAA;;QAEC,IAAI,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE;AAC3C,YAAA,SAAS,CAAgB,IAAI,CAAC,SAAS,EAAE,SAAS;iBAChD,IAAI,CACJ,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,EAClD,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;iBAEpC,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QAChC;;;;;;AAOA,QAAA,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,MAAK;AAC/B,YAAA,IAAI,YAAY,KAAK,IAAI,EAAE;gBAC1B,YAAY,GAAG,IAAI;YACpB;AAEA,YAAA,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE;AAC1B,YAAA,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE;AAC3B,YAAA,IAAI,CAAC,WAAW,GAAG,IAAI;AACxB,QAAA,CAAC,CAAC;IACH;;IAGA,IAAI,GAAA;QACH,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE;YAAE;QAEtC,YAAY,EAAE,KAAK,EAAE;QACrB,YAAY,GAAG,IAAI;QAEnB,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;AAErH,QAAA,MAAM,YAAY,GAAG,CAAC,sBAAsB,CAAC;QAC7C,IAAI,IAAI,CAAC,UAAU,EAAE;YAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;AAE3D,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;AAEvF,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC;;AAG9D,QAAA,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;;AAGpD,QAAA,IAAI,IAAI,CAAC,aAAa,EAAE,IAAI,OAAO,EAAE;AACpC,YAAA,SAAS,CAAa,OAAO,EAAE,OAAO;AACpC,iBAAA,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;iBAClD,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QAChC;AAEA,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;AACrB,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;;AAGlB,QAAA,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;AAClE,aAAA,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;aAClD,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;;AAG/B,QAAA,SAAS,CAAa,IAAI,CAAC,SAAS,EAAE,OAAO;AAC3C,aAAA,IAAI,CACJ,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,CAAC,EACtG,IAAI,CAAC,CAAC,CAAC,EACP,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;aAEpC,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IAChC;;IAGA,KAAK,GAAA;AACJ,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAAE;AACpB,QAAA,IAAI,YAAY,KAAK,IAAI,EAAE;;;YAG1B,YAAY,GAAG,IAAI;QACpB;AACA,QAAA,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE;AAC1B,QAAA,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE;AAC3B,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI;AACvB,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;IACnB;;IAGA,MAAM,GAAA;AACL,QAAA,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE;IAC3C;IAEU,YAAY,GAAA;AACrB,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,OAAO;YAAE,IAAI,CAAC,MAAM,EAAE;IAC9C;IAEU,YAAY,GAAA;AACrB,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,OAAO;YAAE,IAAI,CAAC,IAAI,EAAE;IAC5C;IAEU,YAAY,GAAA;AACrB,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,OAAO;YAAE,IAAI,CAAC,KAAK,EAAE;IAC7C;AAEA;;;AAGG;IACK,eAAe,GAAA;AACtB,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE;AACxB,QAAA,MAAM,GAAG,GAAuD;YAC/D,cAAc,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YACzG,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YACnG,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YACnG,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC;YACvG,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC;YACjG,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC;YACjG,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC;YAClG,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;SAC9F;AACD,QAAA,OAAO,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;IAC7B;uGA/IY,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAApB,oBAAoB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,EAAA,GAAA,EAAA,EAAA,iBAAA,EAAA,KAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,MAAA,EAAA,cAAA,EAAA,MAAA,EAAA,QAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,OAAA,EAAA,gBAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,EAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAApB,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBAVhC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,QAAQ,EAAE,eAAe;AACzB,oBAAA,UAAU,EAAE,IAAI;AAChB,oBAAA,QAAQ,EAAE,aAAa;AACvB,oBAAA,IAAI,EAAE;AACL,wBAAA,SAAS,EAAE,gBAAgB;AAC3B,wBAAA,cAAc,EAAE,gBAAgB;AAChC,wBAAA,cAAc,EAAE;AAChB;AACD,iBAAA;;;AClDD;;;;;;;;;;AAUG;;ACDH;AACA,MAAM,cAAc,GAAiC,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC;AAElG;;;;;;;;;;AAUG;MAgEU,uBAAuB,CAAA;IAC1B,MAAM,GAAG,KAAK,CAAC,QAAQ;+EAAwB;AAExD;;;;;AAKG;AACO,IAAA,MAAM,CAAC,MAAoB,EAAA;AACpC,QAAA,OAAO,MAAM,CAAC,IAAI,KAAK,MAAM,GAAG,MAAM,GAAG,IAAI;IAC9C;AAEA;;;;;;;AAOG;AACO,IAAA,SAAS,CAAC,OAA2B,EAAA;AAC9C,QAAA,OAAO,cAAc,CAAC,QAAQ,CAAC,OAAwB,CAAC,GAAI,OAAyB,GAAG,MAAM;IAC/F;AAEA;;;;;;;AAOG;IACO,QAAQ,CAAC,MAAoB,EAAE,KAAY,EAAA;QACpD,KAAK,CAAC,eAAe,EAAE;QAEvB,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,CAAC,QAAQ,EAAE;YAC9C;QACD;QACA,MAAM,CAAC,QAAQ,EAAE;IAClB;uGAxCY,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAvB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,uBAAuB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,iFAAA,EAAA,cAAA,EAAA,kBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA1DzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoDT,EAAA,QAAA,EAAA,IAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAtDS,OAAO,oFAAE,kBAAkB,EAAA,QAAA,EAAA,yBAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,EAAA,MAAA,EAAA,SAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,oBAAoB,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,aAAA,EAAA,WAAA,EAAA,SAAA,EAAA,eAAA,EAAA,UAAA,EAAA,SAAA,EAAA,YAAA,EAAA,QAAA,CAAA,EAAA,OAAA,EAAA,CAAA,cAAA,EAAA,QAAA,EAAA,QAAA,CAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,yBAAyB,kFAAE,wBAAwB,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,UAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,WAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FA4DpG,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBA/DnC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,QAAQ,EAAE,kBAAkB;AAC5B,oBAAA,UAAU,EAAE,IAAI;oBAChB,OAAO,EAAE,CAAC,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,wBAAwB,CAAC;oBACjH,eAAe,EAAE,uBAAuB,CAAC,MAAM;AAC/C,oBAAA,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDT,CAAA,CAAA;AACD,oBAAA,IAAI,EAAE;AACL,wBAAA,KAAK,EAAE,kBAAkB;AACzB,wBAAA,KAAK,EAAE;AACP;AACD,iBAAA;;;ACjFD;;;;;;;;;;;;;;;AAeG;AACI,MAAM,iBAAiB,GAAsB;IACnD,MAAM,CAAC,SAAkB,EAAE,MAA4B,EAAA;QACtD,MAAM,GAAG,GAAI,SAA8B,CAAC,eAAe,CAAC,uBAAuB,CAAC;AACpF,QAAA,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAE9B,OAAO;AACN,YAAA,MAAM,CAAC,IAA0B,EAAA;;;;gBAIhC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC;AACnC,gBAAA,GAAG,CAAC,iBAAiB,CAAC,YAAY,EAAE;YACrC,CAAC;YACD,OAAO,GAAA;gBACN,GAAG,CAAC,OAAO,EAAE;YACd;SACA;IACF;;;ACrCD;;AAEG;AAEH;;ACJA;;AAEG;;;;"}
1
+ {"version":3,"file":"ng-hub-ui-buttons.mjs","sources":["../../../projects/buttons/src/lib/tokens/dropdown.token.ts","../../../projects/buttons/src/lib/components/btn/button.component.ts","../../../projects/buttons/src/lib/components/btn/button.component.html","../../../projects/buttons/src/lib/components/fab/fab.component.ts","../../../projects/buttons/src/lib/components/fab/fab.component.html","../../../projects/buttons/src/lib/components/speed-dial/speed-dial.component.ts","../../../projects/buttons/src/lib/components/speed-dial/speed-dial.component.html","../../../projects/buttons/src/lib/components/speed-dial/speed-dial-item/speed-dial-item.component.ts","../../../projects/buttons/src/lib/components/speed-dial/speed-dial-item/speed-dial-item.component.html","../../../projects/buttons/src/lib/components/dropdown-panel/dropdown-panel.component.ts","../../../projects/buttons/src/lib/components/dropdown-item/dropdown-item.component.ts","../../../projects/buttons/src/lib/components/dropdown-item/dropdown-item.component.html","../../../projects/buttons/src/lib/components/dropdown-divider/dropdown-divider.component.ts","../../../projects/buttons/src/lib/components/dropdown-header/dropdown-header.component.ts","../../../projects/buttons/src/lib/directives/dropdown.directive.ts","../../../projects/buttons/src/lib/integrations/actions.types.ts","../../../projects/buttons/src/lib/integrations/actions-cell.component.ts","../../../projects/buttons/src/lib/integrations/actions-adapter.ts","../../../projects/buttons/src/public-api.ts","../../../projects/buttons/src/ng-hub-ui-buttons.ts"],"sourcesContent":["import { InjectionToken, Signal } from '@angular/core';\n\n/**\n * Context shared between HubDropdownDirective and its panel/item descendants.\n * Injected by the directive; consumed by HubDropdownPanelComponent and\n * HubDropdownItemComponent to implement closeOnSelect without prop drilling.\n */\nexport interface DropdownContext {\n\t/** Whether clicking an item should close the dropdown. */\n\treadonly closeOnSelect: Signal<boolean>;\n\t/** Imperatively close the dropdown. */\n\tclose(): void;\n}\n\n/** Injection token for DropdownContext. */\nexport const DROPDOWN_CONTEXT = new InjectionToken<DropdownContext>('HubDropdownContext');\n","import { booleanAttribute, ChangeDetectionStrategy, Component, ElementRef, inject, input } from '@angular/core';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { HubBtnSize, HubBtnVariant, HubSemanticColor } from '../../models/button.types';\n\n/**\n * Styled button. Applies `hub-btn` CSS classes computed from signal inputs and\n * renders an optional loading spinner around the projected content.\n *\n * Usable in two interchangeable forms from the same class:\n * - As an element: `<hub-button variant=\"solid\" color=\"primary\">Save</hub-button>`.\n * - As an attribute on any host: `<button hubButton>Save</button>` / `<a hubButton href=\"…\">Link</a>`.\n *\n * Prefer the attribute form on a native `<button>` / `<a>` when you need real button\n * semantics (focus, keyboard activation, form submission). The `<hub-button>` **element**\n * form is only a styling host — a component cannot swap its own host tag for a native\n * `<button>` — so it self-advertises `role=\"button\"`, a focusable `tabindex`, and\n * Enter/Space keyboard activation to stay accessible. The `[hubButton]` attribute form on\n * a native `<button>`/`<a>` adds **none** of these bindings (the host is already\n * interactive; a redundant `role`/`tabindex` would be harmful).\n *\n * **Accessibility caveat:** an element-form `<hub-button>` now reports `role=\"button\"`,\n * so it must not be nested inside another interactive element (a `<button>`, `<a>` or any\n * host that is itself a control), which would produce an invalid nested-interactive tree.\n *\n * **Icons:** project whatever you want as content — the button is icon-library\n * agnostic. The icon's position follows the markup order, and the label/icon gap\n * is the `--hub-button-gap` token:\n *\n * ```html\n * <button hubButton><hub-icon name=\"floppy-disk\" /> Save</button>\n * <button hubButton>Next <hub-icon name=\"arrow-right\" /></button>\n * <button hubButton aria-label=\"Settings\"><hub-icon name=\"gear\" /></button>\n * ```\n */\n@Component({\n\tselector: 'hub-button, [hubButton]',\n\tstandalone: true,\n\ttemplateUrl: './button.component.html',\n\tstyleUrl: './button.component.scss',\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: {\n\t\tclass: 'hub-btn',\n\t\t'[class]': '_hostClass',\n\t\t'[style.--hub-btn-accent]': '_accent',\n\t\t'[attr.disabled]': '_disabledAttr',\n\t\t'[attr.aria-busy]': '_ariaBusy',\n\t\t'[attr.aria-disabled]': '_ariaDisabled',\n\t\t'[attr.role]': '_role',\n\t\t'[attr.tabindex]': '_tabindex',\n\t\t'(keydown)': '_onKeydown($event)'\n\t}\n})\nexport class HubButtonComponent {\n\t/**\n\t * Whether this instance renders as the `<hub-button>` element (vs `[hubButton]` on a\n\t * native host). Read once from the host tag at construction — a static host fact that\n\t * is available immediately (unlike input signals, which are not populated in the\n\t * constructor). Gates the a11y host bindings so they only apply to the element form.\n\t */\n\tprivate readonly _isElementForm = inject(ElementRef).nativeElement.tagName === 'HUB-BUTTON';\n\n\t/** Visual style of the button. */\n\tvariant = input<HubBtnVariant>('solid');\n\n\t/** Semantic color token. */\n\tcolor = input<HubSemanticColor>('primary');\n\n\t/** Size token. */\n\tsize = input<HubBtnSize>('md');\n\n\t/**\n\t * When true, shows the spinner and marks the button **busy and disabled**: it\n\t * reflects `aria-busy=\"true\"`, becomes non-focusable and inert to pointer and\n\t * keyboard, and (like {@link disabled}) reflects the native `disabled` attribute\n\t * so an in-flight submit button cannot be triggered twice.\n\t */\n\tloading = input(false, { transform: booleanAttribute });\n\n\t/**\n\t * Mirrors the native disabled attribute on the host element.\n\t *\n\t * Transformed, so the bare HTML form works: `<button hubButton disabled>` passes the\n\t * empty string an attribute without a value carries, which an untransformed\n\t * `input(false)` rejects at compile time — on the very spelling the name promises.\n\t */\n\tdisabled = input(false, { transform: booleanAttribute });\n\n\t/**\n\t * True while the button must not respond to interaction — either explicitly\n\t * {@link disabled} or busy {@link loading}. Drives the native `disabled`\n\t * reflection, the tab-order removal and the keyboard-activation guard so both\n\t * states are inert through a single source of truth.\n\t */\n\tprivate get _isInert(): boolean {\n\t\treturn this.disabled() || this.loading();\n\t}\n\n\t/** Computed CSS classes applied to the host element via the `[class]` host binding. */\n\tprotected get _hostClass(): string {\n\t\treturn [\n\t\t\t`hub-btn-${this.variant()}`,\n\t\t\t`hub-btn-${this.color()}`,\n\t\t\t`hub-btn-${this.size()}`,\n\t\t\tthis.loading() ? 'hub-btn-loading' : '',\n\t\t\tthis.disabled() ? 'hub-btn-disabled' : ''\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' ');\n\t}\n\n\t/**\n\t * The single semantic accent consumed by the stylesheet (`--hub-btn-accent`),\n\t * from which every visual role (emphasis / subtle / on) is derived at runtime.\n\t *\n\t * Accepts ANY colour: a bareword (a built-in semantic name, a host-registered\n\t * accent or a CSS named colour) resolves to its `--hub-sys-color-<name>` token\n\t * with the bareword itself as the raw fallback, so unregistered names still\n\t * paint; a literal (`#hex`, `rgb()`, `oklch()`, `var(...)`) is passed through\n\t * unchanged. The built-in `hub-btn-<color>` appearance classes remain in place.\n\t */\n\tprotected get _accent(): string | null {\n\t\treturn resolveHubAccent(this.color());\n\t}\n\n\t/** Reflects the inert state (disabled or loading) as the native `disabled` attribute. */\n\tprotected get _disabledAttr(): true | null {\n\t\treturn this._isInert ? true : null;\n\t}\n\n\t/** Announces the busy state to assistive tech while loading. */\n\tprotected get _ariaBusy(): 'true' | null {\n\t\treturn this.loading() ? 'true' : null;\n\t}\n\n\t/**\n\t * Conveys the inert state to assistive tech on the element form, whose custom\n\t * host tag does not natively expose `disabled`. Bound to nothing for the\n\t * attribute form (its native host already exposes the state).\n\t */\n\tprotected get _ariaDisabled(): 'true' | null {\n\t\treturn this._isElementForm && this._isInert ? 'true' : null;\n\t}\n\n\t/**\n\t * Advertises `role=\"button\"` for the element form only. The attribute form binds\n\t * nothing (its native host already exposes the correct role).\n\t */\n\tprotected get _role(): 'button' | null {\n\t\treturn this._isElementForm ? 'button' : null;\n\t}\n\n\t/**\n\t * Makes the element form keyboard-focusable (`0`), or removes it from the tab order\n\t * when inert — disabled or loading (`-1`). Bound to nothing for the attribute form.\n\t */\n\tprotected get _tabindex(): number | null {\n\t\tif (!this._isElementForm) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this._isInert ? -1 : 0;\n\t}\n\n\t/**\n\t * Emulates native button keyboard activation for the element form: Enter or Space\n\t * triggers a click. Space additionally calls `preventDefault()` to stop the page from\n\t * scrolling. No-op for the attribute form (the native host already handles keys) and\n\t * while inert (disabled or loading).\n\t * @param event The originating keyboard event.\n\t */\n\tprotected _onKeydown(event: KeyboardEvent): void {\n\t\tif (!this._isElementForm || this._isInert) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isSpace = event.key === ' ' || event.key === 'Spacebar';\n\n\t\tif (event.key === 'Enter' || isSpace) {\n\t\t\tif (isSpace) {\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\n\t\t\t(event.currentTarget as HTMLElement).click();\n\t\t}\n\t}\n}\n","@if (loading()) {\n\t<span class=\"hub-btn__spinner\" aria-hidden=\"true\"></span>\n}\n<ng-content></ng-content>\n","import {\n\tChangeDetectionStrategy,\n\tComponent,\n\tDestroyRef,\n\tOnInit,\n\tViewEncapsulation,\n\tbooleanAttribute,\n\tinject,\n\tinput,\n\toutput,\n\tsignal\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { fromEvent } from 'rxjs';\nimport { debounceTime } from 'rxjs/operators';\nimport { HubFabPosition, HubFabSize, HubSemanticColor } from '../../models/button.types';\n\n/**\n * Floating Action Button component. Renders fixed in the viewport at the given position.\n * Supports circular and extended (pill with label) variants.\n * When collapseOnScroll is true, an extended FAB collapses to icon-only after 50px scroll.\n * Uses inset-inline-* / inset-block-* CSS logical properties for RTL support.\n *\n * The host element *is* the control — a component cannot swap its own tag for a native\n * `<button>` — so it self-advertises `role=\"button\"`, a focusable `tabindex` and\n * Enter/Space activation to stay reachable without a pointer.\n *\n * **Accessibility caveat:** because it reports `role=\"button\"`, a `<hub-fab>` must not be\n * nested inside another interactive element, which would produce an invalid\n * nested-interactive tree. Give it an accessible name (`aria-label`) when the projected\n * content is only an icon.\n */\n@Component({\n\tselector: 'hub-fab',\n\tstandalone: true,\n\ttemplateUrl: './fab.component.html',\n\tstyleUrl: './fab.component.scss',\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: {\n\t\tclass: 'hub-fab',\n\t\trole: 'button',\n\t\t'[class]': '_hostClass',\n\t\t'[style.--hub-fab-accent]': '_accent',\n\t\t'[attr.tabindex]': '_tabindex',\n\t\t'[attr.aria-disabled]': '_ariaDisabled',\n\t\t'(click)': '_handleClick()',\n\t\t'(keydown)': '_onKeydown($event)'\n\t},\n\t// Exception to emulated encapsulation, for two reasons that both stand on their own.\n\t//\n\t// (1) The stylesheet is a public contract. `hub-fab-color($type)` is exported from\n\t// `ng-hub-ui-buttons/styles` so a consumer can register their own accent, and it emits a\n\t// plain `.hub-fab-<type>` rule from their global sheet. The six built-in colours are\n\t// generated by that very same mixin from this stylesheet, so the built-in and the\n\t// consumer-generated variants only stay interchangeable while both land on the identical\n\t// plain selector — `:host(.hub-fab-primary)` would out-specify every colour a consumer\n\t// registers, and re-generating a built-in from their sheet would silently stop working.\n\t//\n\t// (2) The rules also dress an element that is not in this component's view.\n\t// `HubSpeedDialComponent` renders its trigger as `<button class=\"hub-fab hub-fab-…\">`\n\t// inside its OWN template, and that button is painted by the `.hub-fab` base, size and\n\t// colour rules of this sheet. Scoped rules would never reach it.\n\t//\n\t// Every selector emitted here is namespaced under `.hub-fab*` (plus `.hub-speed-dial\n\t// .hub-fab`, also this library's own), so nothing the library does not own can match.\n\tencapsulation: ViewEncapsulation.None\n})\nexport class HubFabComponent implements OnInit {\n\tcolor = input<HubSemanticColor>('primary');\n\tsize = input<HubFabSize>('standard');\n\t/**\n\t * Renders the pill variant with a projected label.\n\t *\n\t * Transformed, so the bare HTML form works: `<hub-fab extended>` passes the empty\n\t * string an attribute without a value carries, which an untransformed `input(false)`\n\t * rejects at compile time.\n\t */\n\textended = input(false, { transform: booleanAttribute });\n\t/** Fixed viewport position. 9-slot grid including center. */\n\tposition = input<HubFabPosition>('bottom-end');\n\t/** When true, collapses an extended FAB to icon-only on page scroll. */\n\tcollapseOnScroll = input(false, { transform: booleanAttribute });\n\tdisabled = input(false, { transform: booleanAttribute });\n\tfabClick = output<void>();\n\n\t/** Collapse state driven by scroll — only active when extended + collapseOnScroll. */\n\tprotected readonly _collapsed = signal(false);\n\n\tprivate readonly _destroyRef = inject(DestroyRef);\n\n\tprotected get _hostClass(): string {\n\t\treturn [\n\t\t\t`hub-fab-${this.color()}`,\n\t\t\t`hub-fab-${this.size()}`,\n\t\t\t`hub-fab-${this.position()}`,\n\t\t\tthis.extended() && !this._collapsed() ? 'hub-fab-extended' : '',\n\t\t\tthis.disabled() ? 'hub-fab-disabled' : ''\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' ');\n\t}\n\n\t/**\n\t * The semantic accent consumed by the base `.hub-fab` background slot\n\t * (`--hub-fab-accent`). Accepts ANY colour: a bareword (a built-in semantic\n\t * name, a host-registered accent or a CSS named colour) resolves to its\n\t * `--hub-sys-color-<name>` token with the bareword as the raw fallback, so\n\t * unregistered names still paint; a literal (`#hex`, `rgb()`, `oklch()`,\n\t * `var(...)`) is passed through unchanged. Built-in `hub-fab-<color>` classes\n\t * keep overriding the background, so this slot only paints custom / literal\n\t * colours.\n\t */\n\tprotected get _accent(): string | null {\n\t\treturn resolveHubAccent(this.color());\n\t}\n\n\t/**\n\t * Keeps the FAB in the tab order (`0`), or takes it out while disabled (`-1`), the\n\t * way a native button drops out of it — `pointer-events: none` only hides it from\n\t * the pointer.\n\t */\n\tprotected get _tabindex(): number {\n\t\treturn this.disabled() ? -1 : 0;\n\t}\n\n\t/**\n\t * Conveys the disabled state to assistive tech, which a custom host tag cannot\n\t * express through the native `disabled` attribute.\n\t */\n\tprotected get _ariaDisabled(): 'true' | null {\n\t\treturn this.disabled() ? 'true' : null;\n\t}\n\n\t/**\n\t * The host element *is* the button surface — consumers project an icon into it,\n\t * not a control — so activation is read here. `disabled` is re-checked in code\n\t * because the `pointer-events: none` that backs it is a style: a programmatic\n\t * `click()` (or a test) reaches the listener regardless.\n\t */\n\tprotected _handleClick(): void {\n\t\tif (this.disabled()) return;\n\t\tthis.fabClick.emit();\n\t}\n\n\t/**\n\t * Emulates native button keyboard activation: Enter or Space triggers a click.\n\t * Space additionally calls `preventDefault()` to stop the page from scrolling.\n\t * @param event The originating keyboard event.\n\t */\n\tprotected _onKeydown(event: KeyboardEvent): void {\n\t\tif (this.disabled()) return;\n\n\t\tconst isSpace = event.key === ' ' || event.key === 'Spacebar';\n\n\t\tif (event.key === 'Enter' || isSpace) {\n\t\t\tif (isSpace) {\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\n\t\t\t(event.currentTarget as HTMLElement).click();\n\t\t}\n\t}\n\n\tngOnInit(): void {\n\t\tif (!this.collapseOnScroll()) return;\n\n\t\tfromEvent(window, 'scroll', { passive: true })\n\t\t\t.pipe(debounceTime(50), takeUntilDestroyed(this._destroyRef))\n\t\t\t.subscribe(() => {\n\t\t\t\tthis._collapsed.set(window.scrollY > 50);\n\t\t\t});\n\t}\n}\n","<ng-content select=\"[slot=icon]\"></ng-content>\n\n@if (extended() && !_collapsed()) {\n\t<span class=\"hub-fab__label\">\n\t\t<ng-content select=\"[slot=label]\"></ng-content>\n\t</span>\n} @else if (!extended()) {\n\t<ng-content></ng-content>\n}\n","import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, DestroyRef, PLATFORM_ID, inject, input, model, output } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { fromEvent } from 'rxjs';\nimport { filter } from 'rxjs/operators';\nimport { HubFabPosition, HubFabSize, HubSemanticColor } from '../../models/button.types';\n\n/**\n * FAB that expands a stack of HubSpeedDialItemComponent children on click or hover.\n * Supports 4 expansion directions and all 9 FAB viewport positions.\n * Closes automatically on Escape key press.\n *\n * The hover trigger is watched on the host, not on the trigger button: the host box holds\n * the button, the action items and the gap between them, so travelling from the trigger to\n * an item never leaves it. On the button, that trip is a `mouseleave` and the menu is gone\n * before the pointer arrives.\n */\n@Component({\n\tselector: 'hub-speed-dial',\n\tstandalone: true,\n\ttemplateUrl: './speed-dial.component.html',\n\tstyleUrl: './speed-dial.component.scss',\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: {\n\t\tclass: 'hub-speed-dial',\n\t\t'[class]': '_hostClass',\n\t\t'(mouseenter)': '_onHostEnter()',\n\t\t'(mouseleave)': '_onHostLeave()'\n\t}\n})\nexport class HubSpeedDialComponent {\n\tcolor = input<HubSemanticColor>('primary');\n\tsize = input<HubFabSize>('standard');\n\tposition = input<HubFabPosition>('bottom-end');\n\tdirection = input<'up' | 'down' | 'left' | 'right'>('up');\n\ttrigger = input<'click' | 'hover'>('click');\n\tisOpen = model(false);\n\topened = output<void>();\n\tclosed = output<void>();\n\n\tprivate readonly _destroyRef = inject(DestroyRef);\n\n\tprotected get _hostClass(): string {\n\t\treturn [\n\t\t\t`hub-speed-dial-${this.color()}`,\n\t\t\t`hub-speed-dial-${this.position()}`,\n\t\t\t`hub-speed-dial-${this.direction()}`,\n\t\t\tthis.isOpen() ? 'hub-speed-dial-open' : ''\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' ');\n\t}\n\n\t/**\n\t * The semantic accent painted on the inner `.hub-fab` trigger button through its\n\t * `--hub-fab-accent` slot. Accepts ANY colour: a bareword (a built-in semantic\n\t * name, a host-registered accent or a CSS named colour) resolves to its\n\t * `--hub-sys-color-<name>` token with the bareword as the raw fallback, so\n\t * unregistered names still paint; a literal (`#hex`, `rgb()`, `oklch()`,\n\t * `var(...)`) is passed through unchanged. Built-in `hub-fab-<color>` classes on\n\t * the trigger keep overriding the background, so this slot only paints custom /\n\t * literal colours.\n\t */\n\tprotected get _accent(): string | null {\n\t\treturn resolveHubAccent(this.color());\n\t}\n\n\tconstructor() {\n\t\t// Escape-to-close relies on DOM events; inert on the server (SSR/prerender).\n\t\tif (isPlatformBrowser(inject(PLATFORM_ID))) {\n\t\t\tfromEvent<KeyboardEvent>(inject(DOCUMENT), 'keydown')\n\t\t\t\t.pipe(\n\t\t\t\t\tfilter((e) => e.key === 'Escape' && this.isOpen()),\n\t\t\t\t\ttakeUntilDestroyed(this._destroyRef)\n\t\t\t\t)\n\t\t\t\t.subscribe(() => this.close());\n\t\t}\n\t}\n\n\tprotected _onHostEnter(): void {\n\t\tif (this.trigger() === 'hover') this.open();\n\t}\n\n\tprotected _onHostLeave(): void {\n\t\tif (this.trigger() === 'hover') this.close();\n\t}\n\n\t/** Toggle the speed dial open/closed. */\n\ttoggle(): void {\n\t\tthis.isOpen() ? this.close() : this.open();\n\t}\n\n\t/** Open the speed dial and emit the opened event. */\n\topen(): void {\n\t\tthis.isOpen.set(true);\n\t\tthis.opened.emit();\n\t}\n\n\t/** Close the speed dial and emit the closed event. */\n\tclose(): void {\n\t\tthis.isOpen.set(false);\n\t\tthis.closed.emit();\n\t}\n}\n","<button\n\tclass=\"hub-fab\"\n\t[class]=\"'hub-fab-' + color() + ' hub-fab-' + size()\"\n\t[style.--hub-fab-accent]=\"_accent\"\n\t(click)=\"trigger() === 'click' && toggle()\"\n\ttype=\"button\"\n\t[attr.aria-expanded]=\"isOpen()\"\n\taria-haspopup=\"true\"\n>\n\t<ng-content select=\"[hubTrigger]\"></ng-content>\n</button>\n\n@if (isOpen()) {\n\t<div class=\"hub-speed-dial__actions\" [attr.data-direction]=\"direction()\">\n\t\t<ng-content></ng-content>\n\t</div>\n}\n","import { ChangeDetectionStrategy, Component, booleanAttribute, input, output } from '@angular/core';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { HubSemanticColor } from '../../../models/button.types';\n\n/**\n * Secondary action item rendered inside HubSpeedDialComponent.\n * Emits itemClick when activated. Supports an optional label tooltip.\n */\n@Component({\n\tselector: 'hub-speed-dial-item',\n\tstandalone: true,\n\ttemplateUrl: './speed-dial-item.component.html',\n\tstyleUrl: './speed-dial-item.component.scss',\n\tchangeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class HubSpeedDialItemComponent {\n\t/** CSS class of the icon rendered in the action button (e.g. `'bi bi-pencil'`). */\n\ticon = input.required<string>();\n\t/** Tooltip label shown next to the action button. */\n\tlabel = input('');\n\tcolor = input<HubSemanticColor | 'default'>('default');\n\t/**\n\t * Makes the action button inert.\n\t *\n\t * Transformed, so the bare HTML form works: `<hub-speed-dial-item disabled>` passes the\n\t * empty string an attribute without a value carries, which an untransformed\n\t * `input(false)` rejects at compile time.\n\t */\n\tdisabled = input(false, { transform: booleanAttribute });\n\titemClick = output<void>();\n\n\t/**\n\t * The semantic accent painted on the action button through its\n\t * `--hub-speed-dial-item-accent` slot. Accepts ANY colour: a bareword (a\n\t * built-in semantic name, a host-registered accent or a CSS named colour)\n\t * resolves to its `--hub-sys-color-<name>` token with the bareword as the raw\n\t * fallback, so unregistered names still paint; a literal (`#hex`, `rgb()`,\n\t * `oklch()`, `var(...)`) is passed through unchanged. Returns `null` for the\n\t * `default` colour and for the built-in classes, which paint themselves — the\n\t * slot only takes effect for custom / literal colours.\n\t */\n\tprotected get _accent(): string | null {\n\t\treturn this.color() === 'default' ? null : resolveHubAccent(this.color());\n\t}\n}\n","@if (label()) {\n\t<span class=\"hub-speed-dial-item__label\">{{ label() }}</span>\n}\n<button\n\tclass=\"hub-speed-dial-item__btn\"\n\t[class]=\"'hub-speed-dial-item__btn--' + color()\"\n\t[style.--hub-speed-dial-item-accent]=\"_accent\"\n\t[disabled]=\"disabled() || null\"\n\t(click)=\"itemClick.emit()\"\n\ttype=\"button\"\n\t[attr.aria-label]=\"label() || icon()\"\n>\n\t<i [class]=\"icon()\" aria-hidden=\"true\"></i>\n</button>\n","import { ChangeDetectionStrategy, Component, input } from '@angular/core';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { HubSemanticColor } from '../../models/button.types';\n\n/**\n * Styled container for dropdown content.\n * Renders a shadowed panel with an optional semantic color top-border accent.\n * Place hub-dropdown-item, hub-dropdown-divider, and hub-dropdown-header children inside.\n */\n@Component({\n\tselector: 'hub-dropdown-panel',\n\tstandalone: true,\n\ttemplate: `<ng-content></ng-content>`,\n\tstyleUrl: './dropdown-panel.component.scss',\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: {\n\t\tclass: 'hub-dropdown-panel',\n\t\t'[class]': '_hostClass',\n\t\t'[style.--hub-dropdown-panel-accent]': '_accent'\n\t}\n})\nexport class HubDropdownPanelComponent {\n\t/** Adds a semantic color accent to the panel top border. */\n\tcolor = input<HubSemanticColor | 'default'>('default');\n\n\tprotected get _hostClass(): string {\n\t\treturn this.color() !== 'default' ? `hub-dropdown-panel-${this.color()}` : '';\n\t}\n\n\t/**\n\t * The semantic accent painted on the panel top border through the\n\t * `--hub-dropdown-panel-accent` slot. Accepts ANY colour: a bareword (a built-in\n\t * semantic name, a host-registered accent or a CSS named colour) resolves to its\n\t * `--hub-sys-color-<name>` token with the bareword as the raw fallback, so\n\t * unregistered names still paint; a literal (`#hex`, `rgb()`, `oklch()`,\n\t * `var(...)`) is passed through unchanged. Returns `null` for the `default`\n\t * colour (the border keeps its neutral colour) and for the built-in classes,\n\t * which paint their own thicker accent — the slot only takes effect for custom /\n\t * literal colours.\n\t */\n\tprotected get _accent(): string | null {\n\t\treturn this.color() === 'default' ? null : resolveHubAccent(this.color());\n\t}\n}\n","import { ChangeDetectionStrategy, Component, booleanAttribute, input, output } from '@angular/core';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { HubSemanticColor } from '../../models/button.types';\n\n/**\n * Menu item for use inside HubDropdownPanelComponent.\n * Emits itemClick when activated. Supports an optional icon, selected state and semantic color.\n */\n@Component({\n\tselector: 'hub-dropdown-item',\n\tstandalone: true,\n\ttemplateUrl: './dropdown-item.component.html',\n\tstyleUrl: './dropdown-item.component.scss',\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: {\n\t\tclass: 'hub-dropdown-item',\n\t\t'[class]': '_hostClass',\n\t\t'[style.--hub-dropdown-item-accent]': '_accent'\n\t}\n})\nexport class HubDropdownItemComponent {\n\tcolor = input<HubSemanticColor | 'default'>('default');\n\t/** Optional CSS class of the icon rendered before the label (e.g. `'bi bi-pencil'`). */\n\ticon = input<string>();\n\t/**\n\t * Makes the item inert.\n\t *\n\t * Transformed, so the bare HTML form works: `<hub-dropdown-item disabled>` passes the\n\t * empty string an attribute without a value carries, which an untransformed\n\t * `input(false)` rejects at compile time. Same for {@link selected}.\n\t */\n\tdisabled = input(false, { transform: booleanAttribute });\n\t/** Shows a checkmark indicator when selected. */\n\tselected = input(false, { transform: booleanAttribute });\n\titemClick = output<void>();\n\n\tprotected get _hostClass(): string {\n\t\treturn [\n\t\t\tthis.color() !== 'default' ? `hub-dropdown-item-${this.color()}` : '',\n\t\t\tthis.disabled() ? 'hub-dropdown-item-disabled' : '',\n\t\t\tthis.selected() ? 'hub-dropdown-item-selected' : ''\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' ');\n\t}\n\n\t/**\n\t * The semantic accent painted as the item label colour through the\n\t * `--hub-dropdown-item-accent` slot. Accepts ANY colour: a bareword (a built-in\n\t * semantic name, a host-registered accent or a CSS named colour) resolves to its\n\t * `--hub-sys-color-<name>` token with the bareword as the raw fallback, so\n\t * unregistered names still paint; a literal (`#hex`, `rgb()`, `oklch()`,\n\t * `var(...)`) is passed through unchanged. Returns `null` for the `default`\n\t * colour (the item inherits its colour) and for the built-in classes, which\n\t * paint themselves — the slot only takes effect for custom / literal colours.\n\t */\n\tprotected get _accent(): string | null {\n\t\treturn this.color() === 'default' ? null : resolveHubAccent(this.color());\n\t}\n\n\tprotected _handleClick(): void {\n\t\tif (this.disabled()) return;\n\t\tthis.itemClick.emit();\n\t}\n}\n","<button class=\"hub-dropdown-item__inner\" type=\"button\" [disabled]=\"disabled() || null\" (click)=\"_handleClick()\">\n\t@if (icon()) {\n\t\t<i [class]=\"icon()\" aria-hidden=\"true\"></i>\n\t}\n\t<span class=\"hub-dropdown-item__label\"><ng-content></ng-content></span>\n\t@if (selected()) {\n\t\t<span class=\"hub-dropdown-item__check\" aria-hidden=\"true\">✓</span>\n\t}\n</button>\n","import { ChangeDetectionStrategy, Component } from '@angular/core';\n\n/** Horizontal separator for grouping items inside HubDropdownPanelComponent. */\n@Component({\n\tselector: 'hub-dropdown-divider',\n\tstandalone: true,\n\ttemplate: '',\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: {\n\t\tclass: 'hub-dropdown-divider',\n\t\trole: 'separator',\n\t\t'aria-hidden': 'true'\n\t},\n\tstyles: [\n\t\t`\n\t\t\t:host {\n\t\t\t\tdisplay: block;\n\t\t\t\theight: 1px;\n\t\t\t\tbackground: var(--hub-dropdown-divider-color, var(--hub-sys-color-border-subtle, #dee2e6));\n\t\t\t\tmargin: var(--hub-ref-space-1, 0.25rem) 0;\n\t\t\t}\n\t\t`\n\t]\n})\nexport class HubDropdownDividerComponent {}\n","import { ChangeDetectionStrategy, Component } from '@angular/core';\n\n/** Group label for organizing items inside HubDropdownPanelComponent. */\n@Component({\n\tselector: 'hub-dropdown-header',\n\tstandalone: true,\n\ttemplate: `<ng-content></ng-content>`,\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: { class: 'hub-dropdown-header' },\n\tstyles: [\n\t\t`\n\t\t\t:host {\n\t\t\t\tdisplay: block;\n\t\t\t\tpadding: 0.375rem var(--hub-dropdown-header-padding-x, var(--hub-ref-space-3, 1rem)) 0.1875rem;\n\t\t\t\tfont-size: var(--hub-dropdown-header-font-size, var(--hub-ref-font-size-xs, 0.75rem));\n\t\t\t\tfont-weight: var(--hub-ref-font-weight-bold, 700);\n\t\t\t\tcolor: var(--hub-dropdown-header-color, var(--hub-sys-color-text-subtle, #6c757d));\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tletter-spacing: 0.06em;\n\t\t\t}\n\t\t`\n\t]\n})\nexport class HubDropdownHeaderComponent {}\n","import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport {\n\tDestroyRef,\n\tDirective,\n\tElementRef,\n\tPLATFORM_ID,\n\tTemplateRef,\n\tViewContainerRef,\n\tbooleanAttribute,\n\tinject,\n\tinput,\n\tmodel,\n\toutput,\n\tsignal\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Subscription, fromEvent } from 'rxjs';\nimport { filter, take } from 'rxjs/operators';\nimport { OverlayService } from 'ng-hub-ui-utils';\nimport type { OverlayRef, ConnectionPosition } from 'ng-hub-ui-utils';\nimport { HubDropdownPlacement } from '../models/button.types';\n\n/**\n * The one dropdown currently open, anywhere on the page.\n *\n * Closing on click-outside already made a second one *usually* replace the first, since\n * opening it is itself a click outside the first. Usually is not a guarantee: a dropdown\n * opened from code — a keyboard shortcut, a menu restored after a re-render, a table row\n * that opens its own — produces no such click, and two panels stay up at once. Held in a\n * module variable rather than a service because the rule is about the page, not about\n * anything injectable, and a service would make every consumer provide one to get it.\n */\nlet openDropdown: HubDropdownDirective | null = null;\n\n/**\n * Turns any host element into a dropdown trigger.\n * Renders an ng-template in a body-level overlay managed by OverlayService (no CDK).\n * When closeOnSelect is true, any click inside the panel closes the overlay automatically.\n *\n * Only one dropdown is open at a time: opening one closes whichever was already open,\n * however it was opened.\n */\n@Directive({\n\tselector: '[hubDropdown]',\n\tstandalone: true,\n\texportAs: 'hubDropdown',\n\thost: {\n\t\t'(click)': '_onHostClick()',\n\t\t'(mouseenter)': '_onHostEnter()',\n\t\t'(mouseleave)': '_onHostLeave()'\n\t}\n})\nexport class HubDropdownDirective {\n\t/** The ng-template to render inside the overlay panel. */\n\ttpl = input.required<TemplateRef<any>>({ alias: 'hubDropdown' });\n\tplacement = input<HubDropdownPlacement>('bottom-start');\n\ttrigger = input<'click' | 'hover'>('click');\n\t/**\n\t * When true, any click inside the panel content closes the dropdown.\n\t *\n\t * Transformed, so the bare HTML form works: `closeOnSelect` on its own passes the empty\n\t * string an attribute without a value carries, which an untransformed `input(true)`\n\t * rejects at compile time. Same for {@link disabled}.\n\t */\n\tcloseOnSelect = input(true, { transform: booleanAttribute });\n\tdisabled = input(false, { transform: booleanAttribute });\n\t/** Vertical offset in pixels between the trigger and the panel. */\n\toffsetY = input(4);\n\tpanelClass = input('');\n\tisOpen = model(false);\n\topened = output<void>();\n\tclosed = output<void>();\n\n\tprivate _overlayRef: OverlayRef | null = null;\n\n\t/**\n\t * How long, in milliseconds, the pointer is allowed to be over neither the trigger nor\n\t * the panel before a hover dropdown closes. The panel is body-level and sits `offsetY`\n\t * away from its trigger, so leaving the trigger is not yet a dismissal — leaving it and\n\t * arriving nowhere is.\n\t */\n\tprivate static readonly HOVER_GRACE_MS = 150;\n\n\tprivate _hoverCloseTimer: ReturnType<typeof setTimeout> | null = null;\n\n\t/** Enter/leave listeners on the attached panel, live only while a hover dropdown is open. */\n\tprivate _panelHover: Subscription | null = null;\n\t/**\n\t * Everything open() subscribes to for this cycle only. take(1) retires each one when it\n\t * fires, but a dropdown closed by Escape, by a scroll or from code never fires them: they\n\t * would survive holding the detached panel and close the NEXT panel on the first click\n\t * inside it, which is the very thing closeOnSelect: false is meant to prevent.\n\t */\n\tprivate _openSubs: Subscription | null = null;\n\n\tprivate readonly _el = inject(ElementRef<HTMLElement>);\n\tprivate readonly _vcr = inject(ViewContainerRef);\n\tprivate readonly _overlay = inject(OverlayService);\n\tprivate readonly _destroyRef = inject(DestroyRef);\n\tprivate readonly _document = inject(DOCUMENT);\n\n\tconstructor() {\n\t\t// Escape-to-close relies on DOM events; inert on the server (SSR/prerender).\n\t\tif (isPlatformBrowser(inject(PLATFORM_ID))) {\n\t\t\tfromEvent<KeyboardEvent>(this._document, 'keydown')\n\t\t\t\t.pipe(\n\t\t\t\t\tfilter((e) => e.key === 'Escape' && this.isOpen()),\n\t\t\t\t\ttakeUntilDestroyed(this._destroyRef)\n\t\t\t\t)\n\t\t\t\t.subscribe(() => this.close());\n\t\t}\n\n\t\t// Torn down silently, not closed. `close()` emits `closed`, and a component that\n\t\t// is already gone has nobody to tell — Angular reports that as NG0953. Two things\n\t\t// have to go: the overlay, which lives on the body and would otherwise outlive the\n\t\t// view that owns it, and this directive's place as the one open dropdown, which\n\t\t// would leave a destroyed instance to be closed by whoever opens the next one.\n\t\tthis._destroyRef.onDestroy(() => {\n\t\t\tif (openDropdown === this) {\n\t\t\t\topenDropdown = null;\n\t\t\t}\n\n\t\t\tthis._stopHoverTracking();\n\t\t\tthis._overlayRef?.detach();\n\t\t\tthis._overlayRef?.dispose();\n\t\t\tthis._overlayRef = null;\n\t\t});\n\t}\n\n\t/** Open the dropdown and mount the overlay, closing whichever one was open. */\n\topen(): void {\n\t\tif (this.disabled() || this.isOpen()) return;\n\n\t\topenDropdown?.close();\n\t\topenDropdown = this;\n\n\t\tconst positionStrategy = this._overlay.position().flexibleConnectedTo(this._el).withPositions(this._buildPositions());\n\n\t\tconst panelClasses = ['hub-dropdown-overlay'];\n\t\tif (this.panelClass()) panelClasses.push(this.panelClass());\n\n\t\tthis._overlayRef = this._overlay.create({ positionStrategy, panelClass: panelClasses });\n\n\t\tconst panelEl = this._overlayRef.attach(this.tpl(), this._vcr);\n\n\t\tthis._openSubs = new Subscription();\n\n\t\t// Close on click-inside when closeOnSelect is true\n\t\tif (this.closeOnSelect() && panelEl) {\n\t\t\tthis._openSubs.add(\n\t\t\t\tfromEvent<MouseEvent>(panelEl, 'click')\n\t\t\t\t\t.pipe(take(1), takeUntilDestroyed(this._destroyRef))\n\t\t\t\t\t.subscribe(() => this.close())\n\t\t\t);\n\t\t}\n\n\t\t// The panel is body-level, so the pointer entering it is a leave as far as the\n\t\t// trigger is concerned. Tracked here so that reaching the panel keeps the dropdown\n\t\t// open, and only leaving the panel too starts the countdown again.\n\t\tif (this.trigger() === 'hover' && panelEl) {\n\t\t\tthis._panelHover = new Subscription();\n\t\t\tthis._panelHover.add(fromEvent(panelEl, 'mouseenter').subscribe(() => this._cancelScheduledClose()));\n\t\t\tthis._panelHover.add(fromEvent(panelEl, 'mouseleave').subscribe(() => this._scheduleHoverClose()));\n\t\t}\n\n\t\tthis.isOpen.set(true);\n\t\tthis.opened.emit();\n\n\t\t// Close on scroll so the panel stays aligned with the trigger\n\t\tthis._openSubs.add(\n\t\t\tfromEvent(this._document, 'scroll', { passive: true, capture: true })\n\t\t\t\t.pipe(take(1), takeUntilDestroyed(this._destroyRef))\n\t\t\t\t.subscribe(() => this.close())\n\t\t);\n\n\t\t// Click-outside detection (document-level). The overlay is mounted without a backdrop\n\t\t// — nothing dims or blocks the page behind an open menu — so this listener is the only\n\t\t// thing that closes it on an outside click. The panel has to be named explicitly:\n\t\t// it hangs off the body, never inside the trigger, so without this every click on\n\t\t// a menu item would read as a click outside and close the dropdown — whatever\n\t\t// `closeOnSelect` says.\n\t\tthis._openSubs.add(\n\t\t\tfromEvent<MouseEvent>(this._document, 'click')\n\t\t\t\t.pipe(\n\t\t\t\t\tfilter(\n\t\t\t\t\t\t(e) =>\n\t\t\t\t\t\t\t!this._el.nativeElement.contains(e.target as Node) &&\n\t\t\t\t\t\t\t!panelEl?.contains(e.target as Node) &&\n\t\t\t\t\t\t\t!!this._overlayRef?.hasAttached()\n\t\t\t\t\t),\n\t\t\t\t\ttake(1),\n\t\t\t\t\ttakeUntilDestroyed(this._destroyRef)\n\t\t\t\t)\n\t\t\t\t.subscribe(() => this.close())\n\t\t);\n\t}\n\n\t/** Close the dropdown and destroy the overlay. */\n\tclose(): void {\n\t\t// Before the guard: a pending hover countdown outlives whatever closed the dropdown\n\t\t// first (Escape, a scroll, a call from code), and would otherwise fire into the next\n\t\t// open one.\n\t\tthis._stopHoverTracking();\n\n\t\t// Same reason: these hold the panel that is about to be detached.\n\t\tthis._openSubs?.unsubscribe();\n\t\tthis._openSubs = null;\n\n\t\tif (!this.isOpen()) return;\n\t\tif (openDropdown === this) {\n\t\t\t// Cleared before the overlay goes, so a listener that closes on the way out\n\t\t\t// cannot find this one still recorded as the open one.\n\t\t\topenDropdown = null;\n\t\t}\n\t\tthis._overlayRef?.detach();\n\t\tthis._overlayRef?.dispose();\n\t\tthis._overlayRef = null;\n\t\tthis.isOpen.set(false);\n\t\tthis.closed.emit();\n\t}\n\n\t/** Toggle between open and closed. */\n\ttoggle(): void {\n\t\tthis.isOpen() ? this.close() : this.open();\n\t}\n\n\tprotected _onHostClick(): void {\n\t\tif (this.trigger() === 'click') this.toggle();\n\t}\n\n\tprotected _onHostEnter(): void {\n\t\tif (this.trigger() !== 'hover') return;\n\n\t\tthis._cancelScheduledClose();\n\t\tthis.open();\n\t}\n\n\t/**\n\t * Leaving the trigger only starts a countdown. Closing here and now would make the\n\t * panel unreachable: it is body-level and offset from the trigger, so the pointer has\n\t * to cross a gap that belongs to neither of them.\n\t */\n\tprotected _onHostLeave(): void {\n\t\tif (this.trigger() !== 'hover') return;\n\n\t\tthis._scheduleHoverClose();\n\t}\n\n\t/** Arms the grace period, replacing any countdown already running. */\n\tprivate _scheduleHoverClose(): void {\n\t\tthis._cancelScheduledClose();\n\n\t\tthis._hoverCloseTimer = setTimeout(() => {\n\t\t\tthis._hoverCloseTimer = null;\n\t\t\tthis.close();\n\t\t}, HubDropdownDirective.HOVER_GRACE_MS);\n\t}\n\n\t/** Disarms the grace period, because the pointer arrived somewhere that counts as inside. */\n\tprivate _cancelScheduledClose(): void {\n\t\tif (this._hoverCloseTimer === null) return;\n\n\t\tclearTimeout(this._hoverCloseTimer);\n\t\tthis._hoverCloseTimer = null;\n\t}\n\n\t/** Drops both halves of the hover bookkeeping: the countdown and the panel listeners. */\n\tprivate _stopHoverTracking(): void {\n\t\tthis._cancelScheduledClose();\n\t\tthis._panelHover?.unsubscribe();\n\t\tthis._panelHover = null;\n\t}\n\n\t/**\n\t * Translates HubDropdownPlacement tokens to ConnectionPosition arrays.\n\t * The OverlayPosition tries each entry in order, using the first that fits.\n\t */\n\tprivate _buildPositions(): ConnectionPosition[] {\n\t\tconst o = this.offsetY();\n\t\tconst map: Record<HubDropdownPlacement, ConnectionPosition[]> = {\n\t\t\t'bottom-start': [{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: o }],\n\t\t\tbottom: [{ originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: o }],\n\t\t\t'bottom-end': [{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: o }],\n\t\t\t'top-start': [{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -o }],\n\t\t\ttop: [{ originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -o }],\n\t\t\t'top-end': [{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -o }],\n\t\t\tstart: [{ originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center', offsetX: -o }],\n\t\t\tend: [{ originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center', offsetX: o }]\n\t\t};\n\t\treturn map[this.placement()];\n\t}\n}\n","/**\n * Framework-neutral description of one table row's actions.\n *\n * The shape mirrors (structurally) the contract other ng-hub-ui libraries expose for\n * optional action hosting — `ng-hub-ui-paginable`'s `HubPaginableActionsAdapter` — so\n * this adapter can be wired into them without either package importing the other. It is\n * the same arrangement `hubFormControlAdapter` already uses for the table's inputs.\n *\n * Everything here is already resolved for the row: no predicates, no streams. A host\n * library that lets consumers write those resolves them before describing the cell.\n */\n\n/** Where a menu panel opens relative to its trigger. */\nexport type HubRowMenuPlacement = 'top-start' | 'top' | 'top-end' | 'start' | 'end' | 'bottom-start' | 'bottom' | 'bottom-end';\n\n/** One thing a person can do to a row. */\nexport interface HubRowActionItem {\n\ticon?: string;\n\tlabel?: string;\n\ttooltip?: string;\n\tvariant?: string;\n\tcolor?: string;\n\t/** Drawn and refused — not absent. An absence cannot say «not right now». */\n\tdisabled: boolean;\n\tonSelect: () => void;\n}\n\nexport interface HubRowButtonAction extends HubRowActionItem {\n\tkind: 'button';\n}\n\nexport interface HubRowMenuAction extends Omit<HubRowActionItem, 'onSelect'> {\n\tkind: 'menu';\n\tplacement?: HubRowMenuPlacement;\n\titems: ReadonlyArray<HubRowActionItem>;\n}\n\nexport type HubRowAction = HubRowButtonAction | HubRowMenuAction;\n\nexport interface HubActionsCellConfig {\n\tactions: ReadonlyArray<HubRowAction>;\n}\n\n/** Live handle to the actions created by {@link hubActionsAdapter}. */\nexport interface HubActionsHandle {\n\tupdate(config: HubActionsCellConfig): void;\n\tdestroy(): void;\n}\n\n/** What a host library injects to have its row actions drawn by this library. */\nexport interface HubActionsAdapter {\n\tcreate(container: unknown, config: HubActionsCellConfig): HubActionsHandle;\n}\n","import { NgClass } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, input } from '@angular/core';\nimport { HubButtonComponent } from '../components/btn/button.component';\nimport { HubDropdownItemComponent } from '../components/dropdown-item/dropdown-item.component';\nimport { HubDropdownPanelComponent } from '../components/dropdown-panel/dropdown-panel.component';\nimport { HubDropdownDirective } from '../directives/dropdown.directive';\nimport { HubBtnVariant } from '../models/button.types';\nimport { HubActionsCellConfig, HubRowAction, HubRowMenuAction } from './actions.types';\n\n/** The appearances this library draws; anything else falls back to `soft`. */\nconst KNOWN_VARIANTS: ReadonlyArray<HubBtnVariant> = ['solid', 'outline', 'soft', 'ghost', 'link'];\n\n/**\n * One table row's actions, drawn with the design system's own button and dropdown.\n *\n * Exists so the adapter can create a single component instead of assembling a directive,\n * a template reference and a panel by hand: `hubDropdown` needs a host element and an\n * `ng-template`, which is natural in a template and awkward imperatively.\n *\n * It knows nothing about tables. Its input is the neutral description a host library\n * hands over, which is what keeps `ng-hub-ui-buttons` free of any dependency on the\n * library that renders it.\n */\n@Component({\n\tselector: 'hub-actions-cell',\n\tstandalone: true,\n\timports: [NgClass, HubButtonComponent, HubDropdownDirective, HubDropdownPanelComponent, HubDropdownItemComponent],\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\ttemplate: `\n\t\t@for (action of config().actions; track $index) {\n\t\t\t@if (asMenu(action); as menu) {\n\t\t\t\t<button\n\t\t\t\t\thubButton\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t[variant]=\"asVariant(menu.variant)\"\n\t\t\t\t\t[color]=\"menu.color ?? 'neutral'\"\n\t\t\t\t\t[disabled]=\"menu.disabled\"\n\t\t\t\t\t[attr.title]=\"menu.tooltip ?? null\"\n\t\t\t\t\t[attr.aria-label]=\"menu.tooltip ?? menu.label ?? null\"\n\t\t\t\t\t[hubDropdown]=\"panel\"\n\t\t\t\t\t[placement]=\"menu.placement ?? 'bottom-end'\"\n\t\t\t\t\t(click)=\"$event.stopPropagation()\"\n\t\t\t\t>\n\t\t\t\t\t@if (menu.icon) {\n\t\t\t\t\t\t<i [ngClass]=\"menu.icon\" aria-hidden=\"true\"></i>\n\t\t\t\t\t}\n\t\t\t\t\t@if (menu.label) {\n\t\t\t\t\t\t<span>{{ menu.label }}</span>\n\t\t\t\t\t}\n\t\t\t\t</button>\n\n\t\t\t\t<ng-template #panel>\n\t\t\t\t\t<hub-dropdown-panel>\n\t\t\t\t\t\t@for (item of menu.items; track $index) {\n\t\t\t\t\t\t\t<hub-dropdown-item [icon]=\"item.icon\" [disabled]=\"item.disabled\" (itemClick)=\"item.onSelect()\">\n\t\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t\t</hub-dropdown-item>\n\t\t\t\t\t\t}\n\t\t\t\t\t</hub-dropdown-panel>\n\t\t\t\t</ng-template>\n\t\t\t} @else {\n\t\t\t\t<button\n\t\t\t\t\thubButton\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t[variant]=\"asVariant(action.variant)\"\n\t\t\t\t\t[color]=\"action.color ?? 'neutral'\"\n\t\t\t\t\t[disabled]=\"action.disabled\"\n\t\t\t\t\t[attr.title]=\"action.tooltip ?? null\"\n\t\t\t\t\t[attr.aria-label]=\"action.tooltip ?? action.label ?? null\"\n\t\t\t\t\t(click)=\"onSelect(action, $event)\"\n\t\t\t\t>\n\t\t\t\t\t@if (action.icon) {\n\t\t\t\t\t\t<i [ngClass]=\"action.icon\" aria-hidden=\"true\"></i>\n\t\t\t\t\t}\n\t\t\t\t\t@if (action.label) {\n\t\t\t\t\t\t<span>{{ action.label }}</span>\n\t\t\t\t\t}\n\t\t\t\t</button>\n\t\t\t}\n\t\t}\n\t`,\n\thost: {\n\t\tclass: 'hub-actions-cell',\n\t\tstyle: 'display: inline-flex; align-items: center; gap: var(--hub-ref-space-2, 0.5rem);'\n\t}\n})\nexport class HubActionsCellComponent {\n\treadonly config = input.required<HubActionsCellConfig>();\n\n\t/**\n\t * Narrows an action to a menu, for the template's `@if (…; as menu)`.\n\t *\n\t * A type guard rather than a `kind` comparison in the template, because the template\n\t * cannot narrow a union on its own and would otherwise need a cast at every field.\n\t */\n\tprotected asMenu(action: HubRowAction): HubRowMenuAction | null {\n\t\treturn action.kind === 'menu' ? action : null;\n\t}\n\n\t/**\n\t * Narrows the host's open vocabulary onto this library's closed one.\n\t *\n\t * A host names appearances in its own terms and leaves the type open — the table, for\n\t * one, has a `default` that means «the plain bordered button I have always drawn», a\n\t * name this library does not have. Anything unrecognised becomes `soft`, which is what\n\t * a row action looks like here, rather than a type error in code that works.\n\t */\n\tprotected asVariant(variant: string | undefined): HubBtnVariant {\n\t\treturn KNOWN_VARIANTS.includes(variant as HubBtnVariant) ? (variant as HubBtnVariant) : 'soft';\n\t}\n\n\t/**\n\t * Runs the action and keeps the click from reaching the row underneath.\n\t *\n\t * A host that draws these inside clickable rows — a table whose rows open a detail\n\t * page — would otherwise navigate away every time somebody pressed a row action, and\n\t * the action's own effect would be lost with the screen it happened on. A click on an\n\t * action is never a click on what surrounds it, whoever surrounds it.\n\t */\n\tprotected onSelect(action: HubRowAction, event: Event): void {\n\t\tevent.stopPropagation();\n\n\t\tif (action.kind === 'menu' || action.disabled) {\n\t\t\treturn;\n\t\t}\n\t\taction.onSelect();\n\t}\n}\n","import { ViewContainerRef } from '@angular/core';\nimport { HubActionsCellComponent } from './actions-cell.component';\nimport { HubActionsAdapter, HubActionsCellConfig, HubActionsHandle } from './actions.types';\n\n/**\n * Draws a host library's row actions with this library's button and dropdown.\n *\n * Register it where the host expects it — for `ng-hub-ui-paginable`:\n *\n * ```ts\n * import { provideHubPaginableActions } from 'ng-hub-ui-paginable';\n * import { hubActionsAdapter } from 'ng-hub-ui-buttons';\n *\n * providers: [provideHubPaginableActions(hubActionsAdapter)];\n * ```\n *\n * The host describes each row's actions in neutral terms and this maps them onto the\n * real components, so neither package imports the other and the application is the only\n * place that knows both exist.\n */\nexport const hubActionsAdapter: HubActionsAdapter = {\n\tcreate(container: unknown, config: HubActionsCellConfig): HubActionsHandle {\n\t\tconst ref = (container as ViewContainerRef).createComponent(HubActionsCellComponent);\n\t\tref.setInput('config', config);\n\n\t\treturn {\n\t\t\tupdate(next: HubActionsCellConfig): void {\n\t\t\t\t// A new object every time, so `input.required` sees a change: the host\n\t\t\t\t// rebuilds the description on each row change and mutating in place would\n\t\t\t\t// leave an OnPush cell showing the previous row's actions.\n\t\t\t\tref.setInput('config', { ...next });\n\t\t\t\tref.changeDetectorRef.markForCheck();\n\t\t\t},\n\t\t\tdestroy(): void {\n\t\t\t\tref.destroy();\n\t\t\t}\n\t\t};\n\t}\n};\n","/*\n * Public API Surface of ng-hub-ui-buttons\n */\n\n// Types\nexport * from './lib/models/button.types';\n\n// Tokens\nexport * from './lib/tokens/dropdown.token';\n\n// Components\nexport * from './lib/components/btn/button.component';\n/**\n * @deprecated Renamed to `HubButtonComponent`. The component now also matches the\n * `[hubButton]` attribute selector, so it replaces the former `HubBtnDirective`.\n */\nexport { HubButtonComponent as HubBtnComponent } from './lib/components/btn/button.component';\n/**\n * @deprecated Replaced by `HubButtonComponent`, which now matches `[hubButton]` itself\n * (and renders the loading spinner in the attribute form too).\n */\nexport { HubButtonComponent as HubBtnDirective } from './lib/components/btn/button.component';\nexport * from './lib/components/fab/fab.component';\nexport * from './lib/components/speed-dial/speed-dial.component';\nexport * from './lib/components/speed-dial/speed-dial-item/speed-dial-item.component';\nexport * from './lib/components/dropdown-panel/dropdown-panel.component';\nexport * from './lib/components/dropdown-item/dropdown-item.component';\nexport * from './lib/components/dropdown-divider/dropdown-divider.component';\nexport * from './lib/components/dropdown-header/dropdown-header.component';\n\n// Directives\nexport * from './lib/directives/dropdown.directive';\n\n// Cross-library integrations\nexport * from './lib/integrations/actions.types';\nexport * from './lib/integrations/actions-cell.component';\nexport * from './lib/integrations/actions-adapter';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;AAcA;MACa,gBAAgB,GAAG,IAAI,cAAc,CAAkB,oBAAoB;;ACXxF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BG;MAmBU,kBAAkB,CAAA;AAC9B;;;;;AAKG;IACc,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC,OAAO,KAAK,YAAY;;IAG3F,OAAO,GAAG,KAAK,CAAgB,OAAO;gFAAC;;IAGvC,KAAK,GAAG,KAAK,CAAmB,SAAS;8EAAC;;IAG1C,IAAI,GAAG,KAAK,CAAa,IAAI;6EAAC;AAE9B;;;;;AAKG;IACH,OAAO,GAAG,KAAK,CAAC,KAAK,+EAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AAEvD;;;;;;AAMG;IACH,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;AAExD;;;;;AAKG;AACH,IAAA,IAAY,QAAQ,GAAA;QACnB,OAAO,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE;IACzC;;AAGA,IAAA,IAAc,UAAU,GAAA;QACvB,OAAO;AACN,YAAA,CAAA,QAAA,EAAW,IAAI,CAAC,OAAO,EAAE,CAAA,CAAE;AAC3B,YAAA,CAAA,QAAA,EAAW,IAAI,CAAC,KAAK,EAAE,CAAA,CAAE;AACzB,YAAA,CAAA,QAAA,EAAW,IAAI,CAAC,IAAI,EAAE,CAAA,CAAE;YACxB,IAAI,CAAC,OAAO,EAAE,GAAG,iBAAiB,GAAG,EAAE;YACvC,IAAI,CAAC,QAAQ,EAAE,GAAG,kBAAkB,GAAG;AACvC;aACC,MAAM,CAAC,OAAO;aACd,IAAI,CAAC,GAAG,CAAC;IACZ;AAEA;;;;;;;;;AASG;AACH,IAAA,IAAc,OAAO,GAAA;AACpB,QAAA,OAAO,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACtC;;AAGA,IAAA,IAAc,aAAa,GAAA;QAC1B,OAAO,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI;IACnC;;AAGA,IAAA,IAAc,SAAS,GAAA;AACtB,QAAA,OAAO,IAAI,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,IAAI;IACtC;AAEA;;;;AAIG;AACH,IAAA,IAAc,aAAa,GAAA;AAC1B,QAAA,OAAO,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,QAAQ,GAAG,MAAM,GAAG,IAAI;IAC5D;AAEA;;;AAGG;AACH,IAAA,IAAc,KAAK,GAAA;QAClB,OAAO,IAAI,CAAC,cAAc,GAAG,QAAQ,GAAG,IAAI;IAC7C;AAEA;;;AAGG;AACH,IAAA,IAAc,SAAS,GAAA;AACtB,QAAA,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;AACzB,YAAA,OAAO,IAAI;QACZ;AAEA,QAAA,OAAO,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC;IAC9B;AAEA;;;;;;AAMG;AACO,IAAA,UAAU,CAAC,KAAoB,EAAA;QACxC,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,QAAQ,EAAE;YAC1C;QACD;AAEA,QAAA,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,KAAK,UAAU;QAE7D,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,OAAO,EAAE;YACrC,IAAI,OAAO,EAAE;gBACZ,KAAK,CAAC,cAAc,EAAE;YACvB;AAEC,YAAA,KAAK,CAAC,aAA6B,CAAC,KAAK,EAAE;QAC7C;IACD;uGApIY,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAlB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,kBAAkB,sgCCpD/B,oHAIA,EAAA,MAAA,EAAA,CAAA,6/OAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDgDa,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAlB9B,SAAS;AACC,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,yBAAyB,cACvB,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACL,wBAAA,KAAK,EAAE,SAAS;AAChB,wBAAA,SAAS,EAAE,YAAY;AACvB,wBAAA,0BAA0B,EAAE,SAAS;AACrC,wBAAA,iBAAiB,EAAE,eAAe;AAClC,wBAAA,kBAAkB,EAAE,WAAW;AAC/B,wBAAA,sBAAsB,EAAE,eAAe;AACvC,wBAAA,aAAa,EAAE,OAAO;AACtB,wBAAA,iBAAiB,EAAE,WAAW;AAC9B,wBAAA,WAAW,EAAE;AACb,qBAAA,EAAA,QAAA,EAAA,oHAAA,EAAA,MAAA,EAAA,CAAA,6/OAAA,CAAA,EAAA;;;AEhCF;;;;;;;;;;;;;;AAcG;MAoCU,eAAe,CAAA;IAC3B,KAAK,GAAG,KAAK,CAAmB,SAAS;8EAAC;IAC1C,IAAI,GAAG,KAAK,CAAa,UAAU;6EAAC;AACpC;;;;;;AAMG;IACH,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;;IAExD,QAAQ,GAAG,KAAK,CAAiB,YAAY;iFAAC;;IAE9C,gBAAgB,GAAG,KAAK,CAAC,KAAK,wFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;IAChE,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;IACxD,QAAQ,GAAG,MAAM,EAAQ;;IAGN,UAAU,GAAG,MAAM,CAAC,KAAK;mFAAC;AAE5B,IAAA,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC;AAEjD,IAAA,IAAc,UAAU,GAAA;QACvB,OAAO;AACN,YAAA,CAAA,QAAA,EAAW,IAAI,CAAC,KAAK,EAAE,CAAA,CAAE;AACzB,YAAA,CAAA,QAAA,EAAW,IAAI,CAAC,IAAI,EAAE,CAAA,CAAE;AACxB,YAAA,CAAA,QAAA,EAAW,IAAI,CAAC,QAAQ,EAAE,CAAA,CAAE;AAC5B,YAAA,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,kBAAkB,GAAG,EAAE;YAC/D,IAAI,CAAC,QAAQ,EAAE,GAAG,kBAAkB,GAAG;AACvC;aACC,MAAM,CAAC,OAAO;aACd,IAAI,CAAC,GAAG,CAAC;IACZ;AAEA;;;;;;;;;AASG;AACH,IAAA,IAAc,OAAO,GAAA;AACpB,QAAA,OAAO,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACtC;AAEA;;;;AAIG;AACH,IAAA,IAAc,SAAS,GAAA;AACtB,QAAA,OAAO,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC;IAChC;AAEA;;;AAGG;AACH,IAAA,IAAc,aAAa,GAAA;AAC1B,QAAA,OAAO,IAAI,CAAC,QAAQ,EAAE,GAAG,MAAM,GAAG,IAAI;IACvC;AAEA;;;;;AAKG;IACO,YAAY,GAAA;QACrB,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AACrB,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;IACrB;AAEA;;;;AAIG;AACO,IAAA,UAAU,CAAC,KAAoB,EAAA;QACxC,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AAErB,QAAA,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,KAAK,UAAU;QAE7D,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,OAAO,EAAE;YACrC,IAAI,OAAO,EAAE;gBACZ,KAAK,CAAC,cAAc,EAAE;YACvB;AAEC,YAAA,KAAK,CAAC,aAA6B,CAAC,KAAK,EAAE;QAC7C;IACD;IAEA,QAAQ,GAAA;AACP,QAAA,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE;YAAE;QAE9B,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;AAC3C,aAAA,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;aAC3D,SAAS,CAAC,MAAK;YACf,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,GAAG,EAAE,CAAC;AACzC,QAAA,CAAC,CAAC;IACJ;uGAxGY,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAf,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,eAAe,8pCCpE5B,4PASA,EAAA,MAAA,EAAA,CAAA,07GAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FD2Da,eAAe,EAAA,UAAA,EAAA,CAAA;kBAnC3B,SAAS;AACC,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,SAAS,cACP,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACL,wBAAA,KAAK,EAAE,SAAS;AAChB,wBAAA,IAAI,EAAE,QAAQ;AACd,wBAAA,SAAS,EAAE,YAAY;AACvB,wBAAA,0BAA0B,EAAE,SAAS;AACrC,wBAAA,iBAAiB,EAAE,WAAW;AAC9B,wBAAA,sBAAsB,EAAE,eAAe;AACvC,wBAAA,SAAS,EAAE,gBAAgB;AAC3B,wBAAA,WAAW,EAAE;qBACb,EAAA,aAAA,EAkBc,iBAAiB,CAAC,IAAI,EAAA,QAAA,EAAA,4PAAA,EAAA,MAAA,EAAA,CAAA,07GAAA,CAAA,EAAA;;;AE1DtC;;;;;;;;;AASG;MAcU,qBAAqB,CAAA;IACjC,KAAK,GAAG,KAAK,CAAmB,SAAS;8EAAC;IAC1C,IAAI,GAAG,KAAK,CAAa,UAAU;6EAAC;IACpC,QAAQ,GAAG,KAAK,CAAiB,YAAY;iFAAC;IAC9C,SAAS,GAAG,KAAK,CAAmC,IAAI;kFAAC;IACzD,OAAO,GAAG,KAAK,CAAoB,OAAO;gFAAC;IAC3C,MAAM,GAAG,KAAK,CAAC,KAAK;+EAAC;IACrB,MAAM,GAAG,MAAM,EAAQ;IACvB,MAAM,GAAG,MAAM,EAAQ;AAEN,IAAA,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC;AAEjD,IAAA,IAAc,UAAU,GAAA;QACvB,OAAO;AACN,YAAA,CAAA,eAAA,EAAkB,IAAI,CAAC,KAAK,EAAE,CAAA,CAAE;AAChC,YAAA,CAAA,eAAA,EAAkB,IAAI,CAAC,QAAQ,EAAE,CAAA,CAAE;AACnC,YAAA,CAAA,eAAA,EAAkB,IAAI,CAAC,SAAS,EAAE,CAAA,CAAE;YACpC,IAAI,CAAC,MAAM,EAAE,GAAG,qBAAqB,GAAG;AACxC;aACC,MAAM,CAAC,OAAO;aACd,IAAI,CAAC,GAAG,CAAC;IACZ;AAEA;;;;;;;;;AASG;AACH,IAAA,IAAc,OAAO,GAAA;AACpB,QAAA,OAAO,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACtC;AAEA,IAAA,WAAA,GAAA;;QAEC,IAAI,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE;AAC3C,YAAA,SAAS,CAAgB,MAAM,CAAC,QAAQ,CAAC,EAAE,SAAS;iBAClD,IAAI,CACJ,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,EAClD,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;iBAEpC,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QAChC;IACD;IAEU,YAAY,GAAA;AACrB,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,OAAO;YAAE,IAAI,CAAC,IAAI,EAAE;IAC5C;IAEU,YAAY,GAAA;AACrB,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,OAAO;YAAE,IAAI,CAAC,KAAK,EAAE;IAC7C;;IAGA,MAAM,GAAA;AACL,QAAA,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE;IAC3C;;IAGA,IAAI,GAAA;AACH,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;AACrB,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;IACnB;;IAGA,KAAK,GAAA;AACJ,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;IACnB;uGAxEY,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAArB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,qBAAqB,4iCC/BlC,0dAiBA,EAAA,MAAA,EAAA,CAAA,w2CAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDca,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBAbjC,SAAS;AACC,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gBAAgB,cACd,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACL,wBAAA,KAAK,EAAE,gBAAgB;AACvB,wBAAA,SAAS,EAAE,YAAY;AACvB,wBAAA,cAAc,EAAE,gBAAgB;AAChC,wBAAA,cAAc,EAAE;AAChB,qBAAA,EAAA,QAAA,EAAA,0dAAA,EAAA,MAAA,EAAA,CAAA,w2CAAA,CAAA,EAAA;;;AEzBF;;;AAGG;MAQU,yBAAyB,CAAA;;IAErC,IAAI,GAAG,KAAK,CAAC,QAAQ;6EAAU;;IAE/B,KAAK,GAAG,KAAK,CAAC,EAAE;8EAAC;IACjB,KAAK,GAAG,KAAK,CAA+B,SAAS;8EAAC;AACtD;;;;;;AAMG;IACH,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;IACxD,SAAS,GAAG,MAAM,EAAQ;AAE1B;;;;;;;;;AASG;AACH,IAAA,IAAc,OAAO,GAAA;QACpB,OAAO,IAAI,CAAC,KAAK,EAAE,KAAK,SAAS,GAAG,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1E;uGA5BY,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAzB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,yBAAyB,qmBCftC,sbAcA,EAAA,MAAA,EAAA,CAAA,u9DAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDCa,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBAPrC,SAAS;AACC,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,qBAAqB,EAAA,UAAA,EACnB,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,sbAAA,EAAA,MAAA,EAAA,CAAA,u9DAAA,CAAA,EAAA;;;AEThD;;;;AAIG;MAaU,yBAAyB,CAAA;;IAErC,KAAK,GAAG,KAAK,CAA+B,SAAS;8EAAC;AAEtD,IAAA,IAAc,UAAU,GAAA;AACvB,QAAA,OAAO,IAAI,CAAC,KAAK,EAAE,KAAK,SAAS,GAAG,sBAAsB,IAAI,CAAC,KAAK,EAAE,CAAA,CAAE,GAAG,EAAE;IAC9E;AAEA;;;;;;;;;;AAUG;AACH,IAAA,IAAc,OAAO,GAAA;QACpB,OAAO,IAAI,CAAC,KAAK,EAAE,KAAK,SAAS,GAAG,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1E;uGArBY,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAzB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,yBAAyB,yVAT3B,CAAA,yBAAA,CAA2B,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,wwDAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FASzB,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBAZrC,SAAS;+BACC,oBAAoB,EAAA,UAAA,EAClB,IAAI,EAAA,QAAA,EACN,CAAA,yBAAA,CAA2B,mBAEpB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACL,wBAAA,KAAK,EAAE,oBAAoB;AAC3B,wBAAA,SAAS,EAAE,YAAY;AACvB,wBAAA,qCAAqC,EAAE;AACvC,qBAAA,EAAA,MAAA,EAAA,CAAA,wwDAAA,CAAA,EAAA;;;ACfF;;;AAGG;MAaU,wBAAwB,CAAA;IACpC,KAAK,GAAG,KAAK,CAA+B,SAAS;8EAAC;;AAEtD,IAAA,IAAI,GAAG,KAAK;wFAAU;AACtB;;;;;;AAMG;IACH,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;;IAExD,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;IACxD,SAAS,GAAG,MAAM,EAAQ;AAE1B,IAAA,IAAc,UAAU,GAAA;QACvB,OAAO;AACN,YAAA,IAAI,CAAC,KAAK,EAAE,KAAK,SAAS,GAAG,CAAA,kBAAA,EAAqB,IAAI,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE;YACrE,IAAI,CAAC,QAAQ,EAAE,GAAG,4BAA4B,GAAG,EAAE;YACnD,IAAI,CAAC,QAAQ,EAAE,GAAG,4BAA4B,GAAG;AACjD;aACC,MAAM,CAAC,OAAO;aACd,IAAI,CAAC,GAAG,CAAC;IACZ;AAEA;;;;;;;;;AASG;AACH,IAAA,IAAc,OAAO,GAAA;QACpB,OAAO,IAAI,CAAC,KAAK,EAAE,KAAK,SAAS,GAAG,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1E;IAEU,YAAY,GAAA;QACrB,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AACrB,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;IACtB;uGA3CY,wBAAwB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAxB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,wBAAwB,kvBCpBrC,4YASA,EAAA,MAAA,EAAA,CAAA,65EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDWa,wBAAwB,EAAA,UAAA,EAAA,CAAA;kBAZpC,SAAS;AACC,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,mBAAmB,cACjB,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACL,wBAAA,KAAK,EAAE,mBAAmB;AAC1B,wBAAA,SAAS,EAAE,YAAY;AACvB,wBAAA,oCAAoC,EAAE;AACtC,qBAAA,EAAA,QAAA,EAAA,4YAAA,EAAA,MAAA,EAAA,CAAA,65EAAA,CAAA,EAAA;;;AEhBF;MAsBa,2BAA2B,CAAA;uGAA3B,2BAA2B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA3B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,2BAA2B,8LAlB7B,EAAE,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,qKAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAkBA,2BAA2B,EAAA,UAAA,EAAA,CAAA;kBArBvC,SAAS;+BACC,sBAAsB,EAAA,UAAA,EACpB,IAAI,EAAA,QAAA,EACN,EAAE,mBACK,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACL,wBAAA,KAAK,EAAE,sBAAsB;AAC7B,wBAAA,IAAI,EAAE,WAAW;AACjB,wBAAA,aAAa,EAAE;AACf,qBAAA,EAAA,MAAA,EAAA,CAAA,qKAAA,CAAA,EAAA;;;ACVF;MAqBa,0BAA0B,CAAA;uGAA1B,0BAA0B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA1B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,0BAA0B,gIAjB5B,CAAA,yBAAA,CAA2B,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,yXAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAiBzB,0BAA0B,EAAA,UAAA,EAAA,CAAA;kBApBtC,SAAS;AACC,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,qBAAqB,EAAA,UAAA,EACnB,IAAI,EAAA,QAAA,EACN,CAAA,yBAAA,CAA2B,EAAA,eAAA,EACpB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC,EAAE,KAAK,EAAE,qBAAqB,EAAE,EAAA,MAAA,EAAA,CAAA,yXAAA,CAAA,EAAA;;;ACcvC;;;;;;;;;AASG;AACH,IAAI,YAAY,GAAgC,IAAI;AAEpD;;;;;;;AAOG;MAWU,oBAAoB,CAAA;;IAEhC,GAAG,GAAG,KAAK,CAAC,QAAQ,0EAAqB,KAAK,EAAE,aAAa,EAAA,CAAG;IAChE,SAAS,GAAG,KAAK,CAAuB,cAAc;kFAAC;IACvD,OAAO,GAAG,KAAK,CAAoB,OAAO;gFAAC;AAC3C;;;;;;AAMG;IACH,aAAa,GAAG,KAAK,CAAC,IAAI,qFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;IAC5D,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;;IAExD,OAAO,GAAG,KAAK,CAAC,CAAC;gFAAC;IAClB,UAAU,GAAG,KAAK,CAAC,EAAE;mFAAC;IACtB,MAAM,GAAG,KAAK,CAAC,KAAK;+EAAC;IACrB,MAAM,GAAG,MAAM,EAAQ;IACvB,MAAM,GAAG,MAAM,EAAQ;IAEf,WAAW,GAAsB,IAAI;AAE7C;;;;;AAKG;AACK,IAAA,OAAgB,cAAc,GAAG,GAAG;IAEpC,gBAAgB,GAAyC,IAAI;;IAG7D,WAAW,GAAwB,IAAI;AAC/C;;;;;AAKG;IACK,SAAS,GAAwB,IAAI;AAE5B,IAAA,GAAG,GAAG,MAAM,EAAC,UAAuB,EAAC;AACrC,IAAA,IAAI,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAC/B,IAAA,QAAQ,GAAG,MAAM,CAAC,cAAc,CAAC;AACjC,IAAA,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC;AAChC,IAAA,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC;AAE7C,IAAA,WAAA,GAAA;;QAEC,IAAI,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE;AAC3C,YAAA,SAAS,CAAgB,IAAI,CAAC,SAAS,EAAE,SAAS;iBAChD,IAAI,CACJ,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,EAClD,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;iBAEpC,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QAChC;;;;;;AAOA,QAAA,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,MAAK;AAC/B,YAAA,IAAI,YAAY,KAAK,IAAI,EAAE;gBAC1B,YAAY,GAAG,IAAI;YACpB;YAEA,IAAI,CAAC,kBAAkB,EAAE;AACzB,YAAA,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE;AAC1B,YAAA,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE;AAC3B,YAAA,IAAI,CAAC,WAAW,GAAG,IAAI;AACxB,QAAA,CAAC,CAAC;IACH;;IAGA,IAAI,GAAA;QACH,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE;YAAE;QAEtC,YAAY,EAAE,KAAK,EAAE;QACrB,YAAY,GAAG,IAAI;QAEnB,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;AAErH,QAAA,MAAM,YAAY,GAAG,CAAC,sBAAsB,CAAC;QAC7C,IAAI,IAAI,CAAC,UAAU,EAAE;YAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;AAE3D,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;AAEvF,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC;AAE9D,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI,YAAY,EAAE;;AAGnC,QAAA,IAAI,IAAI,CAAC,aAAa,EAAE,IAAI,OAAO,EAAE;YACpC,IAAI,CAAC,SAAS,CAAC,GAAG,CACjB,SAAS,CAAa,OAAO,EAAE,OAAO;AACpC,iBAAA,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;iBAClD,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,CAC/B;QACF;;;;QAKA,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,OAAO,IAAI,OAAO,EAAE;AAC1C,YAAA,IAAI,CAAC,WAAW,GAAG,IAAI,YAAY,EAAE;YACrC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,qBAAqB,EAAE,CAAC,CAAC;YACpG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC;QACnG;AAEA,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;AACrB,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;;QAGlB,IAAI,CAAC,SAAS,CAAC,GAAG,CACjB,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;AAClE,aAAA,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;aAClD,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,CAC/B;;;;;;;AAQD,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CACjB,SAAS,CAAa,IAAI,CAAC,SAAS,EAAE,OAAO;aAC3C,IAAI,CACJ,MAAM,CACL,CAAC,CAAC,KACD,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAc,CAAC;AAClD,YAAA,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAc,CAAC;YACpC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,CAClC,EACD,IAAI,CAAC,CAAC,CAAC,EACP,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;aAEpC,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,CAC/B;IACF;;IAGA,KAAK,GAAA;;;;QAIJ,IAAI,CAAC,kBAAkB,EAAE;;AAGzB,QAAA,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE;AAC7B,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI;AAErB,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAAE;AACpB,QAAA,IAAI,YAAY,KAAK,IAAI,EAAE;;;YAG1B,YAAY,GAAG,IAAI;QACpB;AACA,QAAA,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE;AAC1B,QAAA,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE;AAC3B,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI;AACvB,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;IACnB;;IAGA,MAAM,GAAA;AACL,QAAA,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE;IAC3C;IAEU,YAAY,GAAA;AACrB,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,OAAO;YAAE,IAAI,CAAC,MAAM,EAAE;IAC9C;IAEU,YAAY,GAAA;AACrB,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,OAAO;YAAE;QAEhC,IAAI,CAAC,qBAAqB,EAAE;QAC5B,IAAI,CAAC,IAAI,EAAE;IACZ;AAEA;;;;AAIG;IACO,YAAY,GAAA;AACrB,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,OAAO;YAAE;QAEhC,IAAI,CAAC,mBAAmB,EAAE;IAC3B;;IAGQ,mBAAmB,GAAA;QAC1B,IAAI,CAAC,qBAAqB,EAAE;AAE5B,QAAA,IAAI,CAAC,gBAAgB,GAAG,UAAU,CAAC,MAAK;AACvC,YAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI;YAC5B,IAAI,CAAC,KAAK,EAAE;AACb,QAAA,CAAC,EAAE,oBAAoB,CAAC,cAAc,CAAC;IACxC;;IAGQ,qBAAqB,GAAA;AAC5B,QAAA,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI;YAAE;AAEpC,QAAA,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC;AACnC,QAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI;IAC7B;;IAGQ,kBAAkB,GAAA;QACzB,IAAI,CAAC,qBAAqB,EAAE;AAC5B,QAAA,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE;AAC/B,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI;IACxB;AAEA;;;AAGG;IACK,eAAe,GAAA;AACtB,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE;AACxB,QAAA,MAAM,GAAG,GAAuD;YAC/D,cAAc,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YACzG,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YACnG,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YACnG,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC;YACvG,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC;YACjG,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC;YACjG,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC;YAClG,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;SAC9F;AACD,QAAA,OAAO,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;IAC7B;uGA9OY,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAApB,oBAAoB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,EAAA,GAAA,EAAA,EAAA,iBAAA,EAAA,KAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,MAAA,EAAA,cAAA,EAAA,MAAA,EAAA,QAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,OAAA,EAAA,gBAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,EAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAApB,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBAVhC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,QAAQ,EAAE,eAAe;AACzB,oBAAA,UAAU,EAAE,IAAI;AAChB,oBAAA,QAAQ,EAAE,aAAa;AACvB,oBAAA,IAAI,EAAE;AACL,wBAAA,SAAS,EAAE,gBAAgB;AAC3B,wBAAA,cAAc,EAAE,gBAAgB;AAChC,wBAAA,cAAc,EAAE;AAChB;AACD,iBAAA;;;ACnDD;;;;;;;;;;AAUG;;ACDH;AACA,MAAM,cAAc,GAAiC,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC;AAElG;;;;;;;;;;AAUG;MAgEU,uBAAuB,CAAA;IAC1B,MAAM,GAAG,KAAK,CAAC,QAAQ;+EAAwB;AAExD;;;;;AAKG;AACO,IAAA,MAAM,CAAC,MAAoB,EAAA;AACpC,QAAA,OAAO,MAAM,CAAC,IAAI,KAAK,MAAM,GAAG,MAAM,GAAG,IAAI;IAC9C;AAEA;;;;;;;AAOG;AACO,IAAA,SAAS,CAAC,OAA2B,EAAA;AAC9C,QAAA,OAAO,cAAc,CAAC,QAAQ,CAAC,OAAwB,CAAC,GAAI,OAAyB,GAAG,MAAM;IAC/F;AAEA;;;;;;;AAOG;IACO,QAAQ,CAAC,MAAoB,EAAE,KAAY,EAAA;QACpD,KAAK,CAAC,eAAe,EAAE;QAEvB,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,CAAC,QAAQ,EAAE;YAC9C;QACD;QACA,MAAM,CAAC,QAAQ,EAAE;IAClB;uGAxCY,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAvB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,uBAAuB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,iFAAA,EAAA,cAAA,EAAA,kBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA1DzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoDT,EAAA,QAAA,EAAA,IAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAtDS,OAAO,oFAAE,kBAAkB,EAAA,QAAA,EAAA,yBAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,EAAA,MAAA,EAAA,SAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,oBAAoB,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,aAAA,EAAA,WAAA,EAAA,SAAA,EAAA,eAAA,EAAA,UAAA,EAAA,SAAA,EAAA,YAAA,EAAA,QAAA,CAAA,EAAA,OAAA,EAAA,CAAA,cAAA,EAAA,QAAA,EAAA,QAAA,CAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,yBAAyB,kFAAE,wBAAwB,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,UAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,WAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FA4DpG,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBA/DnC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,QAAQ,EAAE,kBAAkB;AAC5B,oBAAA,UAAU,EAAE,IAAI;oBAChB,OAAO,EAAE,CAAC,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,wBAAwB,CAAC;oBACjH,eAAe,EAAE,uBAAuB,CAAC,MAAM;AAC/C,oBAAA,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDT,CAAA,CAAA;AACD,oBAAA,IAAI,EAAE;AACL,wBAAA,KAAK,EAAE,kBAAkB;AACzB,wBAAA,KAAK,EAAE;AACP;AACD,iBAAA;;;ACjFD;;;;;;;;;;;;;;;AAeG;AACI,MAAM,iBAAiB,GAAsB;IACnD,MAAM,CAAC,SAAkB,EAAE,MAA4B,EAAA;QACtD,MAAM,GAAG,GAAI,SAA8B,CAAC,eAAe,CAAC,uBAAuB,CAAC;AACpF,QAAA,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAE9B,OAAO;AACN,YAAA,MAAM,CAAC,IAA0B,EAAA;;;;gBAIhC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC;AACnC,gBAAA,GAAG,CAAC,iBAAiB,CAAC,YAAY,EAAE;YACrC,CAAC;YACD,OAAO,GAAA;gBACN,GAAG,CAAC,OAAO,EAAE;YACd;SACA;IACF;;;ACrCD;;AAEG;AAEH;;ACJA;;AAEG;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ng-hub-ui-buttons",
3
- "version": "22.11.0",
3
+ "version": "22.11.2",
4
4
  "license": "MIT",
5
5
  "description": "Buttons, FAB, Speed Dial and Dropdown directive for Angular, part of the ng-hub-ui ecosystem",
6
6
  "author": "Carlos Morcillo <carlos.morcillo@me.com> (https://www.carlosmorcillo.com)",
@@ -26,15 +26,20 @@
26
26
  "peerDependencies": {
27
27
  "@angular/common": ">=21.0.0",
28
28
  "@angular/core": ">=21.0.0",
29
+ "ng-hub-ui-ds": ">=22.0.0",
29
30
  "ng-hub-ui-utils": ">=22.7.0"
30
31
  },
32
+ "peerDependenciesMeta": {
33
+ "ng-hub-ui-ds": {
34
+ "optional": true
35
+ }
36
+ },
31
37
  "dependencies": {
32
38
  "tslib": "^2.3.0"
33
39
  },
34
40
  "sideEffects": false,
35
- "module": "fesm2022/ng-hub-ui-buttons.mjs",
36
- "typings": "types/ng-hub-ui-buttons.d.ts",
37
41
  "exports": {
42
+ "./styles": "./styles/_index.scss",
38
43
  "./package.json": {
39
44
  "default": "./package.json"
40
45
  },
@@ -43,5 +48,7 @@
43
48
  "default": "./fesm2022/ng-hub-ui-buttons.mjs"
44
49
  }
45
50
  },
51
+ "module": "fesm2022/ng-hub-ui-buttons.mjs",
52
+ "typings": "types/ng-hub-ui-buttons.d.ts",
46
53
  "type": "module"
47
54
  }
@@ -1,5 +1,5 @@
1
1
  // ─────────────────────────────────────────────────────────────────────────
2
- // hub-btn-theme — one-call token theming for `<hub-button>` / `[hubBtn]`
2
+ // hub-btn-theme — one-call token theming for `<hub-button>` / `[hubButton]`
3
3
  // ─────────────────────────────────────────────────────────────────────────
4
4
  //
5
5
  // Override the key button design tokens in a single include. Every parameter is
@@ -6,7 +6,7 @@
6
6
  //
7
7
  // Then call any mixin to register additional semantic colors:
8
8
  //
9
- // hub-btn, [hubBtn] { @include hub.hub-btn-color-rules('brand'); }
9
+ // hub-button, [hubButton] { @include hub.hub-btn-color-rules('brand'); }
10
10
  // @include hub.hub-fab-color('brand');
11
11
  // @include hub.hub-dropdown-panel-color('brand');
12
12
  // @include hub.hub-dropdown-item-color('brand');
@@ -167,16 +167,32 @@ declare class HubButtonComponent {
167
167
  * Supports circular and extended (pill with label) variants.
168
168
  * When collapseOnScroll is true, an extended FAB collapses to icon-only after 50px scroll.
169
169
  * Uses inset-inline-* / inset-block-* CSS logical properties for RTL support.
170
+ *
171
+ * The host element *is* the control — a component cannot swap its own tag for a native
172
+ * `<button>` — so it self-advertises `role="button"`, a focusable `tabindex` and
173
+ * Enter/Space activation to stay reachable without a pointer.
174
+ *
175
+ * **Accessibility caveat:** because it reports `role="button"`, a `<hub-fab>` must not be
176
+ * nested inside another interactive element, which would produce an invalid
177
+ * nested-interactive tree. Give it an accessible name (`aria-label`) when the projected
178
+ * content is only an icon.
170
179
  */
171
180
  declare class HubFabComponent implements OnInit {
172
181
  color: _angular_core.InputSignal<HubSemanticColor>;
173
182
  size: _angular_core.InputSignal<HubFabSize>;
174
- extended: _angular_core.InputSignal<boolean>;
183
+ /**
184
+ * Renders the pill variant with a projected label.
185
+ *
186
+ * Transformed, so the bare HTML form works: `<hub-fab extended>` passes the empty
187
+ * string an attribute without a value carries, which an untransformed `input(false)`
188
+ * rejects at compile time.
189
+ */
190
+ extended: _angular_core.InputSignalWithTransform<boolean, unknown>;
175
191
  /** Fixed viewport position. 9-slot grid including center. */
176
192
  position: _angular_core.InputSignal<HubFabPosition>;
177
193
  /** When true, collapses an extended FAB to icon-only on page scroll. */
178
- collapseOnScroll: _angular_core.InputSignal<boolean>;
179
- disabled: _angular_core.InputSignal<boolean>;
194
+ collapseOnScroll: _angular_core.InputSignalWithTransform<boolean, unknown>;
195
+ disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
180
196
  fabClick: _angular_core.OutputEmitterRef<void>;
181
197
  /** Collapse state driven by scroll — only active when extended + collapseOnScroll. */
182
198
  protected readonly _collapsed: _angular_core.WritableSignal<boolean>;
@@ -193,6 +209,30 @@ declare class HubFabComponent implements OnInit {
193
209
  * colours.
194
210
  */
195
211
  protected get _accent(): string | null;
212
+ /**
213
+ * Keeps the FAB in the tab order (`0`), or takes it out while disabled (`-1`), the
214
+ * way a native button drops out of it — `pointer-events: none` only hides it from
215
+ * the pointer.
216
+ */
217
+ protected get _tabindex(): number;
218
+ /**
219
+ * Conveys the disabled state to assistive tech, which a custom host tag cannot
220
+ * express through the native `disabled` attribute.
221
+ */
222
+ protected get _ariaDisabled(): 'true' | null;
223
+ /**
224
+ * The host element *is* the button surface — consumers project an icon into it,
225
+ * not a control — so activation is read here. `disabled` is re-checked in code
226
+ * because the `pointer-events: none` that backs it is a style: a programmatic
227
+ * `click()` (or a test) reaches the listener regardless.
228
+ */
229
+ protected _handleClick(): void;
230
+ /**
231
+ * Emulates native button keyboard activation: Enter or Space triggers a click.
232
+ * Space additionally calls `preventDefault()` to stop the page from scrolling.
233
+ * @param event The originating keyboard event.
234
+ */
235
+ protected _onKeydown(event: KeyboardEvent): void;
196
236
  ngOnInit(): void;
197
237
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<HubFabComponent, never>;
198
238
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<HubFabComponent, "hub-fab", never, { "color": { "alias": "color"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "extended": { "alias": "extended"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "collapseOnScroll": { "alias": "collapseOnScroll"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, { "fabClick": "fabClick"; }, never, ["[slot=icon]", "[slot=label]", "*"], true, never>;
@@ -202,6 +242,11 @@ declare class HubFabComponent implements OnInit {
202
242
  * FAB that expands a stack of HubSpeedDialItemComponent children on click or hover.
203
243
  * Supports 4 expansion directions and all 9 FAB viewport positions.
204
244
  * Closes automatically on Escape key press.
245
+ *
246
+ * The hover trigger is watched on the host, not on the trigger button: the host box holds
247
+ * the button, the action items and the gap between them, so travelling from the trigger to
248
+ * an item never leaves it. On the button, that trip is a `mouseleave` and the menu is gone
249
+ * before the pointer arrives.
205
250
  */
206
251
  declare class HubSpeedDialComponent {
207
252
  color: _angular_core.InputSignal<HubSemanticColor>;
@@ -226,6 +271,8 @@ declare class HubSpeedDialComponent {
226
271
  */
227
272
  protected get _accent(): string | null;
228
273
  constructor();
274
+ protected _onHostEnter(): void;
275
+ protected _onHostLeave(): void;
229
276
  /** Toggle the speed dial open/closed. */
230
277
  toggle(): void;
231
278
  /** Open the speed dial and emit the opened event. */
@@ -241,12 +288,19 @@ declare class HubSpeedDialComponent {
241
288
  * Emits itemClick when activated. Supports an optional label tooltip.
242
289
  */
243
290
  declare class HubSpeedDialItemComponent {
244
- /** Icon character or ligature string displayed in the action button. */
291
+ /** CSS class of the icon rendered in the action button (e.g. `'bi bi-pencil'`). */
245
292
  icon: _angular_core.InputSignal<string>;
246
293
  /** Tooltip label shown next to the action button. */
247
294
  label: _angular_core.InputSignal<string>;
248
295
  color: _angular_core.InputSignal<HubSemanticColor | "default">;
249
- disabled: _angular_core.InputSignal<boolean>;
296
+ /**
297
+ * Makes the action button inert.
298
+ *
299
+ * Transformed, so the bare HTML form works: `<hub-speed-dial-item disabled>` passes the
300
+ * empty string an attribute without a value carries, which an untransformed
301
+ * `input(false)` rejects at compile time.
302
+ */
303
+ disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
250
304
  itemClick: _angular_core.OutputEmitterRef<void>;
251
305
  /**
252
306
  * The semantic accent painted on the action button through its
@@ -294,11 +348,18 @@ declare class HubDropdownPanelComponent {
294
348
  */
295
349
  declare class HubDropdownItemComponent {
296
350
  color: _angular_core.InputSignal<HubSemanticColor | "default">;
297
- /** Optional icon character or ligature displayed before the label. */
351
+ /** Optional CSS class of the icon rendered before the label (e.g. `'bi bi-pencil'`). */
298
352
  icon: _angular_core.InputSignal<string | undefined>;
299
- disabled: _angular_core.InputSignal<boolean>;
353
+ /**
354
+ * Makes the item inert.
355
+ *
356
+ * Transformed, so the bare HTML form works: `<hub-dropdown-item disabled>` passes the
357
+ * empty string an attribute without a value carries, which an untransformed
358
+ * `input(false)` rejects at compile time. Same for {@link selected}.
359
+ */
360
+ disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
300
361
  /** Shows a checkmark indicator when selected. */
301
- selected: _angular_core.InputSignal<boolean>;
362
+ selected: _angular_core.InputSignalWithTransform<boolean, unknown>;
302
363
  itemClick: _angular_core.OutputEmitterRef<void>;
303
364
  protected get _hostClass(): string;
304
365
  /**
@@ -342,9 +403,15 @@ declare class HubDropdownDirective {
342
403
  tpl: _angular_core.InputSignal<TemplateRef<any>>;
343
404
  placement: _angular_core.InputSignal<HubDropdownPlacement>;
344
405
  trigger: _angular_core.InputSignal<"click" | "hover">;
345
- /** When true, any click inside the panel content closes the dropdown. */
346
- closeOnSelect: _angular_core.InputSignal<boolean>;
347
- disabled: _angular_core.InputSignal<boolean>;
406
+ /**
407
+ * When true, any click inside the panel content closes the dropdown.
408
+ *
409
+ * Transformed, so the bare HTML form works: `closeOnSelect` on its own passes the empty
410
+ * string an attribute without a value carries, which an untransformed `input(true)`
411
+ * rejects at compile time. Same for {@link disabled}.
412
+ */
413
+ closeOnSelect: _angular_core.InputSignalWithTransform<boolean, unknown>;
414
+ disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
348
415
  /** Vertical offset in pixels between the trigger and the panel. */
349
416
  offsetY: _angular_core.InputSignal<number>;
350
417
  panelClass: _angular_core.InputSignal<string>;
@@ -352,6 +419,23 @@ declare class HubDropdownDirective {
352
419
  opened: _angular_core.OutputEmitterRef<void>;
353
420
  closed: _angular_core.OutputEmitterRef<void>;
354
421
  private _overlayRef;
422
+ /**
423
+ * How long, in milliseconds, the pointer is allowed to be over neither the trigger nor
424
+ * the panel before a hover dropdown closes. The panel is body-level and sits `offsetY`
425
+ * away from its trigger, so leaving the trigger is not yet a dismissal — leaving it and
426
+ * arriving nowhere is.
427
+ */
428
+ private static readonly HOVER_GRACE_MS;
429
+ private _hoverCloseTimer;
430
+ /** Enter/leave listeners on the attached panel, live only while a hover dropdown is open. */
431
+ private _panelHover;
432
+ /**
433
+ * Everything open() subscribes to for this cycle only. take(1) retires each one when it
434
+ * fires, but a dropdown closed by Escape, by a scroll or from code never fires them: they
435
+ * would survive holding the detached panel and close the NEXT panel on the first click
436
+ * inside it, which is the very thing closeOnSelect: false is meant to prevent.
437
+ */
438
+ private _openSubs;
355
439
  private readonly _el;
356
440
  private readonly _vcr;
357
441
  private readonly _overlay;
@@ -366,7 +450,18 @@ declare class HubDropdownDirective {
366
450
  toggle(): void;
367
451
  protected _onHostClick(): void;
368
452
  protected _onHostEnter(): void;
453
+ /**
454
+ * Leaving the trigger only starts a countdown. Closing here and now would make the
455
+ * panel unreachable: it is body-level and offset from the trigger, so the pointer has
456
+ * to cross a gap that belongs to neither of them.
457
+ */
369
458
  protected _onHostLeave(): void;
459
+ /** Arms the grace period, replacing any countdown already running. */
460
+ private _scheduleHoverClose;
461
+ /** Disarms the grace period, because the pointer arrived somewhere that counts as inside. */
462
+ private _cancelScheduledClose;
463
+ /** Drops both halves of the hover bookkeeping: the countdown and the panel listeners. */
464
+ private _stopHoverTracking;
370
465
  /**
371
466
  * Translates HubDropdownPlacement tokens to ConnectionPosition arrays.
372
467
  * The OverlayPosition tries each entry in order, using the first that fits.