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 +35 -17
- package/fesm2022/ng-hub-ui-buttons.mjs +196 -38
- package/fesm2022/ng-hub-ui-buttons.mjs.map +1 -1
- package/package.json +10 -3
- package/styles/_btn-theme.scss +1 -1
- package/styles/_index.scss +1 -1
- package/types/ng-hub-ui-buttons.d.ts +106 -11
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,
|
|
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
|
-
| `
|
|
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 | `
|
|
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,
|
|
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:
|
|
273
|
-
--hub-button-padding-y: 0.
|
|
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.
|
|
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.
|
|
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:
|
|
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:
|
|
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
|
-
|
|
190
|
-
|
|
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, /*
|
|
196
|
-
...(ngDevMode ?
|
|
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\
|
|
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
|
-
|
|
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
|
-
/**
|
|
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
|
-
|
|
340
|
-
|
|
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
|
|
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
|
-
|
|
412
|
-
|
|
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, /*
|
|
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
|
-
/**
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
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
|
-
|
|
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
|
-
|
|
575
|
-
|
|
576
|
-
|
|
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()
|
|
603
|
-
|
|
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()
|
|
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":"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"}
|
|
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":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ng-hub-ui-buttons",
|
|
3
|
-
"version": "22.11.
|
|
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
|
}
|
package/styles/_btn-theme.scss
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ─────────────────────────────────────────────────────────────────────────
|
|
2
|
-
// hub-btn-theme — one-call token theming for `<hub-button>` / `[
|
|
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
|
package/styles/_index.scss
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
//
|
|
7
7
|
// Then call any mixin to register additional semantic colors:
|
|
8
8
|
//
|
|
9
|
-
// hub-
|
|
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
|
-
|
|
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.
|
|
179
|
-
disabled: _angular_core.
|
|
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
|
-
/**
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
-
/**
|
|
346
|
-
|
|
347
|
-
|
|
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.
|