ng-hub-ui-utils 22.12.0 → 22.13.0
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 +167 -25
- package/fesm2022/ng-hub-ui-utils.mjs +275 -15
- package/fesm2022/ng-hub-ui-utils.mjs.map +1 -1
- package/package.json +13 -9
- package/styles/tooltip.scss +5 -1
- package/types/ng-hub-ui-utils.d.ts +107 -4
package/README.md
CHANGED
|
@@ -116,8 +116,8 @@ export class ExampleComponent {
|
|
|
116
116
|
overlayY: 'top'
|
|
117
117
|
}]);
|
|
118
118
|
|
|
119
|
-
//
|
|
120
|
-
const
|
|
119
|
+
// Render a component (or a TemplateRef) into the overlay; you get the host element back
|
|
120
|
+
const overlayElement = overlayRef.attach(MyComponent);
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
```
|
|
@@ -128,9 +128,11 @@ export class ExampleComponent {
|
|
|
128
128
|
this.overlayService.create({ zIndex: 1100 }); // OverlayConfig.zIndex: number | string — takes precedence over the token
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
### 🎯 Popup Service
|
|
131
|
+
### 🎯 Popup Service
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
`PopupService<T>` hosts a dynamically created popup component and runs its show/hide
|
|
134
|
+
transition. It is a concrete class — subclass it when the popup needs its own API, as
|
|
135
|
+
below, or provide it through a factory.
|
|
134
136
|
|
|
135
137
|
```typescript
|
|
136
138
|
import { PopupService } from 'ng-hub-ui-utils';
|
|
@@ -356,16 +358,17 @@ import { GetPipe, UcfirstPipe } from 'ng-hub-ui-utils';
|
|
|
356
358
|
|
|
357
359
|
### 🏷️ Tooltip Directive
|
|
358
360
|
|
|
359
|
-
Add a lightweight, themeable tooltip to any element with the `
|
|
360
|
-
The tooltip is appended to `<body>` (never clipped) and shows on
|
|
361
|
+
Add a lightweight, themeable tooltip to any element with the `HubTooltipDirective`
|
|
362
|
+
(`[hubTooltip]`). The tooltip is appended to `<body>` (never clipped) and shows on
|
|
363
|
+
hover/focus.
|
|
361
364
|
|
|
362
365
|
```typescript
|
|
363
|
-
import {
|
|
366
|
+
import { HubTooltipDirective } from 'ng-hub-ui-utils';
|
|
364
367
|
|
|
365
368
|
@Component({
|
|
366
369
|
standalone: true,
|
|
367
|
-
imports: [
|
|
368
|
-
template: `<button
|
|
370
|
+
imports: [HubTooltipDirective],
|
|
371
|
+
template: `<button hubTooltip="Save changes" hubTooltipPlacement="top">Save</button>`
|
|
369
372
|
})
|
|
370
373
|
export class ExampleComponent {}
|
|
371
374
|
```
|
|
@@ -378,8 +381,40 @@ export class ExampleComponent {}
|
|
|
378
381
|
> @use 'ng-hub-ui-utils/styles/tooltip';
|
|
379
382
|
> ```
|
|
380
383
|
|
|
381
|
-
Inputs: `
|
|
382
|
-
`
|
|
384
|
+
Inputs: `hubTooltip` (text), `hubTooltipPlacement` (`top` | `bottom` | `left` | `right`,
|
|
385
|
+
default `top`), `hubTooltipDelay` (fade ms, default `150`), `hubTooltipOffset` (px, default `8`).
|
|
386
|
+
|
|
387
|
+
> **`TooltipDirective` (`[tooltip]`) is deprecated since 22.9.0.** It still works,
|
|
388
|
+
> unchanged — both directives are thin shells over the same `HubTooltipController` — but its
|
|
389
|
+
> bare input names (`tooltip`, `placement`, `delay`, `offset`) belong to every directive on
|
|
390
|
+
> the element that declares them, which is how it collided with `[hubDropdown]`'s own
|
|
391
|
+
> `placement` and with the `tooltip` input of `<hub-badge>`. Migration is attribute for
|
|
392
|
+
> attribute: `tooltip` → `hubTooltip`, `placement` → `hubTooltipPlacement`,
|
|
393
|
+
> `delay` → `hubTooltipDelay`, `offset` → `hubTooltipOffset`.
|
|
394
|
+
|
|
395
|
+
Show the label **only while the host is truncated** with `HubOverflowTooltipDirective`
|
|
396
|
+
(`[hubOverflowTooltip]`), which tracks truncation live with a `ResizeObserver` and a
|
|
397
|
+
`MutationObserver` and resolves its tooltip through `HUB_TOOLTIP_ADAPTER`:
|
|
398
|
+
|
|
399
|
+
```html
|
|
400
|
+
<span class="label" [hubOverflowTooltip]="item.label">{{ item.label }}</span>
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
The element that is **hovered** and the element that is **measured** need not be the same.
|
|
404
|
+
By default they are, but a control whose text is clipped by a box inside it wants them apart:
|
|
405
|
+
the hover area is the whole control, while the only box that can report truncation is the
|
|
406
|
+
inner one — a child that clips its own text never lets the overflow reach its parent, so
|
|
407
|
+
measuring the parent reports none and the tooltip goes quiet. Point
|
|
408
|
+
`hubOverflowTooltipMeasure` at the inner box with a CSS selector, resolved inside the host:
|
|
409
|
+
|
|
410
|
+
```html
|
|
411
|
+
<div class="chip" [hubOverflowTooltip]="item.label" hubOverflowTooltipMeasure=".chip__title">
|
|
412
|
+
<span class="chip__icon"></span>
|
|
413
|
+
<span class="chip__title">{{ item.label }}</span>
|
|
414
|
+
</div>
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
Unset — or pointing at nothing — the host measures itself, exactly as before.
|
|
383
418
|
|
|
384
419
|
Theme it from any scope with `--hub-tooltip-*` variables:
|
|
385
420
|
|
|
@@ -394,8 +429,14 @@ Theme it from any scope with `--hub-tooltip-*` variables:
|
|
|
394
429
|
|
|
395
430
|
Available tokens: `--hub-tooltip-bg`, `--hub-tooltip-color`, `--hub-tooltip-opacity`,
|
|
396
431
|
`--hub-tooltip-padding-x`, `--hub-tooltip-padding-y`, `--hub-tooltip-border-radius`,
|
|
397
|
-
`--hub-tooltip-font-size`, `--hub-tooltip-
|
|
398
|
-
`--hub-tooltip-
|
|
432
|
+
`--hub-tooltip-font-size`, `--hub-tooltip-font-weight`, `--hub-tooltip-line-height`,
|
|
433
|
+
`--hub-tooltip-max-width`, `--hub-tooltip-zindex`, `--hub-tooltip-transition-duration`,
|
|
434
|
+
`--hub-tooltip-shadow`, `--hub-tooltip-font-family`, `--hub-tooltip-white-space`,
|
|
435
|
+
`--hub-tooltip-text-align`.
|
|
436
|
+
|
|
437
|
+
The last two arrived in 22.10.0, for the tooltip that carries a sentence rather than a
|
|
438
|
+
name: they are set on the **host**, which is the only element you can reach, because the
|
|
439
|
+
bubble itself lives on `<body>`, outside every component's styles.
|
|
399
440
|
|
|
400
441
|
#### Tooltip adapter for other libraries (`hubTooltipAdapter`)
|
|
401
442
|
|
|
@@ -414,10 +455,26 @@ providers: [
|
|
|
414
455
|
];
|
|
415
456
|
```
|
|
416
457
|
|
|
458
|
+
Inside this package the same token works the other way round: `[hubOverflowTooltip]`
|
|
459
|
+
resolves its tooltip through `HUB_TOOLTIP_ADAPTER`, which defaults to `hubTooltipAdapter`.
|
|
460
|
+
Swap it app-wide, or for one subtree, with `provideHubTooltip()`:
|
|
461
|
+
|
|
462
|
+
```ts
|
|
463
|
+
import { provideHubTooltip, HubTooltipAdapter } from 'ng-hub-ui-utils';
|
|
464
|
+
|
|
465
|
+
const myTooltip: HubTooltipAdapter = {
|
|
466
|
+
attach(host, text, options) {
|
|
467
|
+
/* … returns a HubTooltipHandle with update(text) and destroy() */
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
providers: [provideHubTooltip(myTooltip)];
|
|
472
|
+
```
|
|
473
|
+
|
|
417
474
|
Also available: the imperative `HubTooltipController` (engine) and the
|
|
418
|
-
`HubTooltipAdapter` / `HubTooltipHandle` / `HubTooltipOptions`
|
|
419
|
-
ecosystem-wide
|
|
420
|
-
section.
|
|
475
|
+
`HubTooltipAdapter` / `HubTooltipHandle` / `HubTooltipOptions` / `HubTooltipPlacement`
|
|
476
|
+
types. See the ecosystem-wide
|
|
477
|
+
[Synergies & agnosticism](../../README.md#synergies--agnosticism) section.
|
|
421
478
|
|
|
422
479
|
## 🚀 Installation
|
|
423
480
|
|
|
@@ -505,6 +562,20 @@ interface HubTranslationConfig {
|
|
|
505
562
|
|
|
506
563
|
The configuration is also exposed through the `HUB_TRANSLATION_CONFIG` injection token for advanced scenarios.
|
|
507
564
|
|
|
565
|
+
### `HUB_TRANSLATION_PREFIX`
|
|
566
|
+
|
|
567
|
+
Injection token that scopes a library's lookups to a collision-safe `HUBUI.<LIBRARY>.*`
|
|
568
|
+
namespace. `TranslatePipe` resolves the prefixed key first and falls back to the bare key,
|
|
569
|
+
so a flat dictionary that predates the token keeps working untouched.
|
|
570
|
+
|
|
571
|
+
```typescript
|
|
572
|
+
providers: [{ provide: HUB_TRANSLATION_PREFIX, useValue: 'HUBUI.TABLE' }];
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
The adapter types are exported alongside it: `HubTranslationSource`,
|
|
576
|
+
`HubTranslationOverrides`, `HubTranslationAdapterConfig`, `HubTranslationAdapterFactory`
|
|
577
|
+
and the `HUB_TRANSLATION_SOURCE` token `provideHubTranslationAdapter()` registers.
|
|
578
|
+
|
|
508
579
|
### `HubTranslationService`
|
|
509
580
|
|
|
510
581
|
Injectable service that holds the active translations and notifies subscribers when they change.
|
|
@@ -584,6 +655,19 @@ These functions back the i18n system and are exported for direct use:
|
|
|
584
655
|
|
|
585
656
|
- `regExpEscape(text: string): string` - Escapes special characters for RegExp
|
|
586
657
|
- `removeAccents(str: string): string` - Removes accents from text
|
|
658
|
+
- `interpolateString(expr?: string, params?: any, templateMatcher?: RegExp): string` - Replaces `{{ token }}` placeholders
|
|
659
|
+
- `generateUniqueId(length: number): string` - Random alphanumeric id, for a DOM node that needs one
|
|
660
|
+
|
|
661
|
+
### Object Functions
|
|
662
|
+
|
|
663
|
+
- `equals(o1: any, o2: any): boolean` - Deep equality
|
|
664
|
+
- `getValue(target: any, key: string): any` - Reads a nested value by dot-notation key
|
|
665
|
+
- `isObject(item: any): boolean` - Whether the value is a non-array object
|
|
666
|
+
- `mergeDeep(target: any, source: any): any` - Recursive merge; the only deep object helper in the package
|
|
667
|
+
|
|
668
|
+
### Signal Utilities
|
|
669
|
+
|
|
670
|
+
- `debouncedSignal<T>(source: Signal<T>, delay?: number | Signal<number>): Signal<T>` - Mirrors a signal, delaying each change; the delay can itself be a signal
|
|
587
671
|
|
|
588
672
|
### DOM Functions
|
|
589
673
|
|
|
@@ -591,6 +675,10 @@ These functions back the i18n system and are exported for direct use:
|
|
|
591
675
|
- `reflow(element: HTMLElement): DOMRect` - Forces browser reflow
|
|
592
676
|
- `getActiveElement(root?: Document | ShadowRoot): Element | null` - Gets active element including Shadow DOM
|
|
593
677
|
|
|
678
|
+
### Accent Resolution
|
|
679
|
+
|
|
680
|
+
- `resolveHubAccent(value: string | null | undefined): string | null` - The "any colour" accent resolver shared across the family: a bareword becomes `var(--hub-sys-color-<name>, <name>)`, a literal `#hex` / `rgb()` / `oklch()` / `var()` passes through unchanged, and an empty value yields `null`
|
|
681
|
+
|
|
594
682
|
### Colour Functions
|
|
595
683
|
|
|
596
684
|
- `parseColor(value): HubRgb | null` - Parses hex (3/4/6/8), `rgb()`, `hsl()`, `oklch()`, `oklab()`, the 148 CSS named colours and `transparent`, in modern and legacy syntax. No DOM, so it runs under SSR. Returns `null` — never throws — for anything it cannot resolve, `var()` and `currentColor` included
|
|
@@ -621,6 +709,27 @@ These functions back the i18n system and are exported for direct use:
|
|
|
621
709
|
- `hubFocusTrap(zone, element, stopFocusTrap$, refocusOnClick?)` - Creates focus trap for modals/overlays
|
|
622
710
|
- `FOCUSABLE_ELEMENTS_SELECTOR: string` - CSS selector for focusable elements
|
|
623
711
|
|
|
712
|
+
### Drag and Drop
|
|
713
|
+
|
|
714
|
+
The engine-agnostic half of native HTML5 drag and drop, shared by the libraries that
|
|
715
|
+
implement it. The UI primitives — handle, placeholder and preview directives — stay in each
|
|
716
|
+
library, because their selectors and data models differ.
|
|
717
|
+
|
|
718
|
+
- `HubDragDropService` - Root-provided coordinator. A drag spans two component instances and the native `dataTransfer` payload is unreadable during `dragover`, so a shared service is the only reliable channel for what is being dragged and from where. Owners `register()` / `unregister()`; `begin()`, `setTarget()` and the readonly `active` / `target` / `isDragging` signals report the drag in progress. It coordinates state only — it never mutates your collections
|
|
719
|
+
- `moveItemInArray<T>(array, fromIndex, toIndex): void` / `transferArrayItem<T>(source, target, fromIndex, toIndex): void` / `copyArrayItem<T>(source, target, fromIndex, toIndex): void` - In-place array moves, mirroring the `@angular/cdk` helpers of the same names
|
|
720
|
+
- `clamp(value, max)`, `computeTargetIndex(...)`, `toAbsoluteIndex(...)`, `containsNode(...)` - Index arithmetic for sliced and nested lists
|
|
721
|
+
- `resolveDropPosition(...)` with `DropRect` and `DragAxis` - Where a pointer sits relative to an item: `'before'` or `'after'`, on a vertical, horizontal or grid axis
|
|
722
|
+
- `createNativeDragImage(...)` returning `DragImageResult` - Renders the drag preview the browser shows
|
|
723
|
+
- `createPointerDragSession(config: PointerDragSessionConfig): PointerDragSession` - Pointer Events fallback for touch, where native drag events are not delivered
|
|
724
|
+
- Types: `DropPosition`, `DragPointerMode`, `DragContainerRef<T>`, `ActiveDrag<T>`, `DragTarget<T>`, `DragRegistration`
|
|
725
|
+
|
|
726
|
+
### Directives
|
|
727
|
+
|
|
728
|
+
- `HubTooltipDirective` (`[hubTooltip]`) - Tooltip on hover/focus. Inputs: `hubTooltip`, `hubTooltipPlacement`, `hubTooltipDelay`, `hubTooltipOffset`
|
|
729
|
+
- `HubOverflowTooltipDirective` (`[hubOverflowTooltip]`) - Tooltip shown only while the label is truncated. Inputs: `hubOverflowTooltip`, `placement`, `hubOverflowTooltipMeasure` (CSS selector, resolved inside the host, naming the box whose truncation decides it; defaults to the host)
|
|
730
|
+
- `TooltipDirective` (`[tooltip]`) - **Deprecated since 22.9.0**, kept working. Inputs: `tooltip`, `placement`, `delay`, `offset`
|
|
731
|
+
- `provideHubTooltip(adapter: HubTooltipAdapter)` and `HUB_TOOLTIP_ADAPTER` - Swap the implementation behind `[hubOverflowTooltip]`, app-wide or per subtree; defaults to `hubTooltipAdapter`
|
|
732
|
+
|
|
624
733
|
### Pipes
|
|
625
734
|
|
|
626
735
|
#### GetPipe
|
|
@@ -681,18 +790,39 @@ class OverlayService {
|
|
|
681
790
|
}
|
|
682
791
|
|
|
683
792
|
class OverlayRef {
|
|
684
|
-
|
|
793
|
+
// Renders a template or a component into the overlay and returns the host element,
|
|
794
|
+
// not a ComponentRef: the overlay owns the view it created and tears it down itself.
|
|
795
|
+
attach(content: TemplateRef<unknown> | Type<unknown>, viewContainerRef?: ViewContainerRef): HTMLElement;
|
|
685
796
|
detach(): void;
|
|
686
797
|
dispose(): void;
|
|
798
|
+
hasAttached(): boolean;
|
|
687
799
|
updatePosition(): void;
|
|
800
|
+
onBackdropClick(callback: () => void): void;
|
|
801
|
+
// Only the topmost open overlay is told, so a dropdown inside a dialog takes Escape
|
|
802
|
+
// for itself and leaves the dialog open.
|
|
803
|
+
onKeydown(callback: (event: KeyboardEvent) => void): void;
|
|
688
804
|
}
|
|
689
805
|
|
|
690
806
|
class OverlayPosition {
|
|
691
|
-
|
|
807
|
+
// The element the panel is anchored to. The overlay watches it and follows it when it moves.
|
|
808
|
+
readonly origin: HTMLElement | null;
|
|
809
|
+
flexibleConnectedTo(origin: ElementRef | HTMLElement): this;
|
|
692
810
|
withPositions(positions: ConnectionPosition[]): this;
|
|
811
|
+
// `start` / `end` are logical and read from the origin element; this overrides that.
|
|
812
|
+
withDirection(direction: 'ltr' | 'rtl' | null): this;
|
|
693
813
|
}
|
|
694
814
|
```
|
|
695
815
|
|
|
816
|
+
`HUB_DROPDOWN_POSITIONS` is the ready-made fallback chain for a dropdown — below the
|
|
817
|
+
origin, flipping above when there is no room — expressed logically so one list serves
|
|
818
|
+
both text directions:
|
|
819
|
+
|
|
820
|
+
```typescript
|
|
821
|
+
import { HUB_DROPDOWN_POSITIONS } from 'ng-hub-ui-utils';
|
|
822
|
+
|
|
823
|
+
overlayService.position().flexibleConnectedTo(origin).withPositions([...HUB_DROPDOWN_POSITIONS]);
|
|
824
|
+
```
|
|
825
|
+
|
|
696
826
|
#### ScrollBar Service
|
|
697
827
|
|
|
698
828
|
```typescript
|
|
@@ -702,14 +832,26 @@ class ScrollBar {
|
|
|
702
832
|
}
|
|
703
833
|
```
|
|
704
834
|
|
|
705
|
-
#### PopupService
|
|
835
|
+
#### PopupService<T>
|
|
836
|
+
|
|
837
|
+
A concrete generic class, not an abstract one: it takes the popup component type in its
|
|
838
|
+
constructor, and it reads its collaborators with `inject()`, so it has to be created inside
|
|
839
|
+
an injection context — as an `@Injectable()` subclass, or from a factory provider.
|
|
706
840
|
|
|
707
841
|
```typescript
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
842
|
+
class PopupService<T> {
|
|
843
|
+
constructor(componentType: Type<T>);
|
|
844
|
+
open(
|
|
845
|
+
content?: string | TemplateRef<any>,
|
|
846
|
+
templateContext?: any,
|
|
847
|
+
animation?: boolean
|
|
848
|
+
): { windowRef: ComponentRef<T>; transition$: Observable<void> };
|
|
849
|
+
close(animation?: boolean): Observable<void>;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// The nodes and view a popup projects, returned internally by the content resolver.
|
|
853
|
+
class ContentRef {
|
|
854
|
+
constructor(nodes: Node[][], viewRef?: ViewRef, componentRef?: ComponentRef<any>);
|
|
713
855
|
}
|
|
714
856
|
```
|
|
715
857
|
|
|
@@ -729,7 +871,7 @@ This library doesn't include visual components, but support utilities used by ot
|
|
|
729
871
|
| Overlay Service | Flexible overlay positioning system | ng-hub-ui-modal, ng-hub-ui-portal |
|
|
730
872
|
| Focus Trap | Focus management in modals/overlays | ng-hub-ui-modal, ng-hub-ui-portal |
|
|
731
873
|
| Scrollbar | Scrollbar compensation | ng-hub-ui-modal, ng-hub-ui-portal |
|
|
732
|
-
| Popup Service |
|
|
874
|
+
| Popup Service | Host for dynamically created popups | ng-hub-ui-modal, ng-hub-ui-portal |
|
|
733
875
|
| Transitions | Smooth animations | ng-hub-ui-accordion, ng-hub-ui-modal |
|
|
734
876
|
| Type Guards | Type validation functions | ng-hub-ui-stepper |
|
|
735
877
|
| Pipes | Template utilities | All Hub UI components |
|