Angular ユーティリティライブラリ | ng-hub-ui-utils
再利用可能な UI コンポーネント間で共有される、パイプ、フォーカス管理、オーバーレイ、トランジション、翻訳ヘルパーを備えた Angular ユーティリティライブラリ。
インタラクティブなサンプル
一般的な Angular のユースケースでライブラリがどのように動作するかを示すライブサンプルをご覧ください。
ユーティリティパイプ
GetPipe - Access nested properties
user | get:'profile.name'→ John Doeuser | get:'profile.address.city'→ New YorkIsStringPipe - Type checking
'Hello' | isString→ true123 | isString→ falseIsObjectPipe - Object detection
{ a: 1 } | isObject→ true'string' | isObject→ falseUcfirstPipe - Capitalize first letter
'hello world' | ucfirst→ Hello worldUnwrapAsyncPipe - Observable or plain value, same template
status$ | unwrapAsync→ nothing emitted yet'not an observable' | unwrapAsync→ not an observable翻訳サービスとパイプ
TranslatePipe - Basic usage
'welcome' | translate→ Welcome to ng-hub-uiTranslatePipe - With parameters
'greeting' | translate:{ name: 'Carlos' }→ Hello, Carlos!TranslatePipe - Nested keys
'buttons.save' | translate→ Save'buttons.cancel' | translate→ CancelProgrammatic access
translationService.getTranslation('buttons.delete')→ Delete外部 i18n アダプター
すべての Hub UI ライブラリ用に app.config.ts でリアクティブな翻訳ブリッジを設定します。
ユーティリティ関数
Type Guards
isString('hello')→ trueisNumber(42)→ trueisDefined(null)→ falseisDefined('value')→ trueDeep Equality
equals({a:1}, {a:1})→ trueequals([1,2], [1,2])→ trueObject Access
getValue(user, 'profile.name')→ John DoeString Interpolation
interpolateString('Hello {{name}}', {name: 'World'})→ Hello WorldString Utilities
removeAccents('Ñoño café')→ Nono cafepadNumber(5)→ 05フォーカストラップ
Focus Trap Demo
Click "Enable Focus Trap" and try to Tab outside the blue box. Focus will stay trapped inside.
Focus Trap Area
Status: 🔓 Free
Focusable Elements
The selector FOCUSABLE_ELEMENTS_SELECTOR finds all focusable elements.
getFocusableBoundaryElements(container)→ [first, last] elementsスクロールバーのユーティリティ
ScrollBar Service
The ScrollBar service helps manage scrollbar visibility and compensate for layout shifts when hiding scrollbars (e.g., when opening modals).
Use Case: Modal Body Lock
When opening a modal, you typically hide the body scrollbar. The ScrollBar.hide() method handles this automatically and returns a reverter function.
Status: 🔓 Normal scrolling
Code Example
import { inject } from '@angular/core';
import { ScrollBar } from 'ng-hub-ui-utils';
export class ModalService {
private scrollBar = inject(ScrollBar);
private revertScrollbar: (() => void) | null = null;
openModal() {
// Hide scrollbar and get reverter function
this.revertScrollbar = this.scrollBar.hide();
}
closeModal() {
// Restore scrollbar
if (this.revertScrollbar) {
this.revertScrollbar();
this.revertScrollbar = null;
}
}
}オーバーレイシステム
A connected overlay positioned below the trigger, with a backdrop that closes it on outside click.
ツールチップディレクティブ
--hub-tooltip-* variablesウィンドウの端で反転する
Every hint below asks for the default top placement, and none of them carries hubTooltipPlacement. Scroll until one of them reaches the top of your window and hover it: with no room above, it opens downwards. The middle one, which has room on every side, keeps top. Keep scrolling with a label open and it re-decides on the way.
The placement is a preference, not an instruction: it gives way only when the requested side genuinely has no room and the opposite side has more. An overflow on the cross axis is answered by sliding the label back inside, because flipping a centred label from top to bottom leaves it exactly as far over the edge.
TypeScript から開くポップアップ
Nothing open.
CSS トランジションの完了を待つ
- Run a transition to see when the observable completes.
DOM と RxJS のヘルパー
closest()
Click anywhere inside; the helper walks up to the nearest panel.
closest(target, '[data-panel]') → —
reflow()
Replaying an animation means removing the class and adding it back. Without a forced reflow the browser coalesces both into no change at all.
getActiveElement()
Focus either control. The second one lives inside a shadow root.
document.activeElement → —
getActiveElement() → —
runInZone()
Both streams are created with runOutsideAngular; only one is piped through the operator.
| plain subscriber | isInAngularZone() → — |
|---|---|
| piped through runInZone(zone) | isInAngularZone() → — |
| ticks | 0 |
任意の CSS カラーを解析する
Try one:
| parseColor() | { r: 11, g: 110, b: 255, a: 1 } |
|---|---|
| toHex() | #0b6eff |
| rgbToOklch() | { l: 0.58, c: 0.23, h: 260 } |
| isValidColor() | true |
| toRgb() | already parsed — same object back |
| HUB_NAMED_COLORS | not a bareword — 148 in the table |
読みやすい文字色を選ぶ
A highlighted border marks a chip whose ink differs from what --hub-sys-color-*-on paints in CSS.
Translucent ink has to be composited before it is measured
relativeLuminance() ignores alpha, because a translucent colour has no luminance of its own until something is behind it. Measure the ink as written and you are scoring solid black; compositeOver() blends it onto the surface first, which is what the eye is reading.
| relativeLuminance(surface) | 0.5942 |
|---|---|
| contrastRatio(ink, surface) | 12.88:1 |
| …with compositeOver(ink, surface) | 6.73:1 |
sRGB のガマットは円柱ではない
clampToSrgbGamut()
Asking for chroma 0.35 on the amber hue at the current lightness.
false0.1181 つのブランドカラーからパレットを導く
Hue rotation capped at 15°; neutral chroma capped at 0.015. Success and danger stay 173° apart.