Skip to main content
cngx-src documentation
Miscellaneous > Variables

Variables

Variable79

Index

input/mask-presets/registry.ts

ALL_PRESET_KEYS#MaskPresetKey[]
['phone', 'date', 'iban', 'zip']
inflight#unknown
new Map<MaskPresetKey, Promise<void>>()
tables#unknown
signal<MaskPresetTables>({})

forms/input/input-filter.directive.ts

ALPHA#unknown
/[a-z]/i
ALPHANUMERIC#unknown
/[a-z0-9]/i

forms/input/password-strength.directive.ts

ANNOUNCE_DEBOUNCE_MS#number

Default debounce before the strength label is announced, in ms.

400
strengthEqual#unknown
(a: PasswordStrengthResult, b: PasswordStrengthResult): boolean =>
a.score === b.score && a.label === b.label

audio/tone-generator/tone-generator.ts

ATTACK_SEC#number

Attack ramp, seconds — lifts gain from 0 so the oscillator start is click-free.

0.005

Pure OscillatorNode synthesis — no audio assets. Each tone is an oscillator through a per-note gain envelope (5 ms attack, 30 ms release) into the engine's master-volume node. The envelope is not decoration: a bare start()/stop() on a full-amplitude oscillator produces an audible click at both ends; ramping in and out removes it.

create* pure factory (no inject()), so it composes inside the engine and runs against the shared createAudioContextMock in specs.

(deps) => {
  function schedule(
    freq: number,
    durationMs: number,
    opts: ToneOptions | undefined,
    whenSec: number,
  ): void {
    const ctx = deps.context();
    const dest = deps.destination();
    const start = ctx.currentTime + whenSec + (opts?.when ?? 0);
    const durSec = Math.max(durationMs / 1000, MIN_DURATION_SEC);
    const peak = opts?.gain ?? DEFAULT_TONE_GAIN;

    const osc = ctx.createOscillator();
    osc.type = opts?.type ?? 'sine';
    osc.frequency.setValueAtTime(freq, start);

    const env = ctx.createGain();
    const holdStart = start + ATTACK_SEC;
    const releaseStart = start + durSec - RELEASE_SEC;
    env.gain.setValueAtTime(0, start);
    env.gain.linearRampToValueAtTime(peak, holdStart);
    env.gain.setValueAtTime(peak, releaseStart);
    env.gain.linearRampToValueAtTime(0, start + durSec);

    osc.connect(env);
    env.connect(dest);
    osc.start(start);
    osc.stop(start + durSec);
    osc.onended = () => {
      osc.disconnect();
      env.disconnect();
    };
  }

  return {
    tone(freq, durationMs, opts) {
      schedule(freq, durationMs, opts, 0);
    },
    sequence(steps) {
      let offsetSec = 0;
      for (const step of steps) {
        offsetSec += (step.delay ?? 0) / 1000;
        schedule(step.freq, step.duration, { type: step.type, gain: step.gain }, offsetSec);
        offsetSec += Math.max(step.duration / 1000, MIN_DURATION_SEC);
      }
    },
  };
}
DEFAULT_TONE_GAIN#number

Default peak gain for a single tone (before the engine's master volume). Exported so a per-element volume multiplier can scale against the same baseline the generator uses.

0.2
MIN_DURATION_SEC#unknown

A tone shorter than attack+release cannot host both ramps; clamp up to this floor.

ATTACK_SEC + RELEASE_SEC
RELEASE_SEC#number

Release ramp, seconds — drops gain to 0 before stop so the end is click-free.

0.03

chart/chart/template-slots.ts

CHART_SMALL_BREAKPOINT_PX#number

Threshold (px) below which CngxChartSlotContext.small is true. Hardcoded for v1; later releases may make this a config token.

400

audio/config/audio-config.ts

CNGX_AUDIO_DEFAULTS#CngxAudioConfig

Library defaults — English, browser-native.

{
  muted: false,
  volume: 1,
  respectReducedMotion: true,
  debounceMs: 100,
  earcons: {},
}

audio/event-mode/parse-bindings.ts

CNGX_AUDIO_DOM_EVENTS#unknown

DOM events [cngxAudio] may bind an earcon to.

[
  'click',
  'focus',
  'blur',
  'pointerenter',
  'pointerleave',
  'submit',
  'change',
  'input',
] as const
DOM_EVENT_SET#unknown
new Set<string>(CNGX_AUDIO_DOM_EVENTS)
LIFECYCLE_KEYS#unknown

Lifecycle keys that belong to [cngxAudioStatus], rejected here.

[
  'pending',
  'succeeded',
  'failed',
  'loading',
  'refreshing',
  'success',
  'error',
  'idle',
] as const
LIFECYCLE_SET#unknown
new Set<string>(LIFECYCLE_KEYS)

audio/status-mode/parse-status-bindings.ts

CNGX_AUDIO_STATUS_DOM_EVENTS#unknown

DOM-event keys that belong to [cngxAudio], rejected here.

[
  'click',
  'focus',
  'blur',
  'pointerenter',
  'pointerleave',
  'submit',
  'change',
  'input',
] as const
DOM_EVENT_SET#unknown
new Set<string>(CNGX_AUDIO_STATUS_DOM_EVENTS)
STATUS_ALIASES#Readonly>

Lifecycle keys [cngxAudioStatus] accepts, mapped to the canonical AsyncStatus the transition tracker emits. Two friendly aliases are folded in: succeeded -> success and failed -> error, so both the raw status and the past-tense reading parse to the same earcon.

{
  idle: 'idle',
  loading: 'loading',
  pending: 'pending',
  refreshing: 'refreshing',
  success: 'success',
  succeeded: 'success',
  error: 'error',
  failed: 'error',
}

a11y/focus/focus-restore.directive.ts

CNGX_FOCUSABLE_SELECTOR#string

CSS selector matching natively-focusable elements: links with an href, the enabled form controls, and anything with an explicit non-negative tabindex. Form controls carry :not(:disabled) because a disabled control is not in the tab order - without it a descendant probe would count a disabled button as focusable and a restore target could land on an unfocusable element. Single source of truth for "is this focusable" - the element-level CngxFocusRestore predicate matches against it, and descendant probes (e.g. "does this panel contain a focusable child?") query against it. Keeping one selector stops the two uses from drifting apart.

'a[href], button:not(:disabled), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"])'

ui/collection/incremental-list-config.ts

CNGX_INCREMENTAL_LIST_DEFAULTS#CngxIncrementalListConfig

Library defaults - English. Override via provideIncrementalListConfig.

{
  ariaLabels: {
    loading: 'Loading',
    empty: 'Nothing here yet',
    error: 'Failed to load',
    pageError: 'Failed to load more',
    retry: 'Retry',
    endReached: (total) => `All ${total} loaded`,
    loadedMore: (count, total) => `${count} more loaded. ${total} total.`,
  },
}

interactive/nav/nav-config.ts

CNGX_NAV_DEFAULTS#Readonly>

Default nav configuration values.

{
  indent: 12,
  singleAccordion: false,
  animationDuration: 150,
}

ui/paginator/paginator-config.ts

CNGX_PAGINATOR_DEFAULTS#CngxPaginatorConfig

Library defaults - English. Override via provideCngxPaginatorConfig.

{
  ariaLabels: {
    label: 'Pagination',
    first: 'First page',
    previous: 'Previous page',
    next: 'Next page',
    last: 'Last page',
    page: (page) => `Page ${page}`,
    morePages: 'More pages',
    itemsPerPage: 'Items per page',
    goToPage: 'Go to page',
    pageOfPages: 'Select page',
    loadMore: 'Load more',
    allLoaded: (total) => `All ${total} loaded`,
    bucket: (label) => label,
    emptyBucket: (label) => `${label}, no items`,
    bucketGroup: 'Categories',
    railPosition: 'Page position',
  },
  announcements: {
    pageChange: (page, totalPages) => `Page ${page} of ${totalPages}`,
    loading: 'Loading',
    updated: 'Updated',
  },
  formats: {
    // The readout segments render the formatter output as sanitised HTML, so the
    // current value (the page, or the item range) is emphasised with `<b>`;
    // Angular's sanitiser keeps `<b>` and strips anything dangerous.
    range: (start, end, total) => `<b>${start}-${end}</b> of ${total}`,
    pageStatus: (page, totalPages) => `Page <b>${page}</b> of ${totalPages}`,
  },
  // Includes the brain's default pageSize (10) so the trigger value is always a
  // member of the panel; a common data-table ladder, locale-neutral.
  pageSizeOptions: [10, 25, 50, 100],
}

ui/paginator/paginator-glyphs.ts

CNGX_PAGINATOR_GLYPHS#unknown

Default text glyphs for the paginator segments. Internal and non-exported - mirrors CNGX_SELECT_GLYPHS. The library ships no icon font; these unicode marks are the out-of-the-box chevrons and the overflow ellipsis. Consumers restyle visually via CSS rather than by swapping these characters.

Centralised so the chevron / ellipsis literals live in one place instead of being duplicated across the segment classes.

{
  /** First-page nav (double left-pointing angle quotation mark). */
  first: '«',
  /** Previous-page nav (single left-pointing angle quotation mark). */
  previous: '‹',
  /** Next-page nav (single right-pointing angle quotation mark). */
  next: '›',
  /** Last-page nav (double right-pointing angle quotation mark). */
  last: '»',
  /** Ellipsis trigger that opens the hidden-pages overflow menu. */
  more: '…',
  /** Dropdown caret on the page-size / page-of-pages select triggers. */
  caret: '▾',
} as const

interactive/menu/submenu-defaults.ts

CNGX_SUBMENU_TRY_FALLBACKS#unknown

Recommended position-try-fallbacks chain for menu submenu popovers.

Consumers wire the const on the submenu's cngxPopover element:

<div cngxPopover [positionTryFallbacks]="CNGX_SUBMENU_TRY_FALLBACKS">
  <!-- submenu items -->
</div>

The chain matches the projects/forms/select/shared/select-base.css:759 precedent (flip-block, flip-inline, flip-block flip-inline) — flip-inline is the dominant submenu clip case (right submenu hits the viewport right edge → flips to the left side of its parent item), flip-block covers the vertical case, and the composed form covers diagonal clipping.

CngxMenuItemSubmenu emits a one-shot dev-mode warning when a submenu popover ships without positionTryFallbacks — the const is documented as the canonical opt-in.

Typed as a string-literal tuple via as const rather than the PopoverPositionTryFallback union from @cngx/common/popover — the cross-entry-point import would reverse the existing popover -> interactive dependency direction and break ng-packagr. Consumers binding the const to [positionTryFallbacks] get compile-time type checking from the input's typed signature on the popover side.

Object.freeze([
  'flip-inline',
  'flip-block',
  'flip-block flip-inline',
] as const)

audio/engine/audio-engine.ts

createAudioEngine#CngxAudioEngineFactory

Create the audio engine: composes the autoplay gate, tone generator, and debouncer over one lazily-created shared AudioContext. Reduced-motion muting reuses the existing injectMediaQuery('(prefers-reduced-motion: reduce)') primitive rather than adding another matchMedia reader.

The four mute conditions are enforced centrally in play()/tone()/ sequence(): global mute, reduced-motion, and autoplay-not-armed here; per-element [audioDisabled] in the directives.

Runs in an injection context (calls inject() for DOCUMENT, DestroyRef, the tone-generator factory, and the reduced-motion query). The engine instance is resolved through CNGX_AUDIO_ENGINE_FACTORY; scope it to a subtree with provideCngxAudioAt(...) rather than calling this directly.

(options) => {
  const doc = inject(DOCUMENT);
  const destroyRef = inject(DestroyRef);
  const toneGeneratorFactory = inject(CNGX_AUDIO_TONE_GENERATOR_FACTORY);
  const config = injectAudioConfig();
  const reducedMotion = injectMediaQuery('(prefers-reduced-motion: reduce)');

  const muted = signal(config.muted);
  const volume = signal(clampVolume(config.volume));
  const status = signal<AudioStatus>('idle');
  const lastPlayed = signal<string | null>(null);

  const gate = createAutoplayGate({ target: doc, destroyRef });
  const debouncer = createDebouncer({ windowMs: config.debounceMs });
  const earcons = new Map<string, EarconConfig>(
    Object.entries({ ...CNGX_AUDIO_DEFAULT_EARCONS, ...config.earcons }),
  );

  let context: BaseAudioContext | null = null;
  let masterGain: GainNode | null = null;

  const contextFactory =
    options?.contextFactory ??
    ((): BaseAudioContext | null => {
      const view = doc.defaultView as
        | (Window & {
            AudioContext?: typeof AudioContext;
            webkitAudioContext?: typeof AudioContext;
          })
        | null;
      const Ctor = view?.AudioContext ?? view?.webkitAudioContext;
      return Ctor ? new Ctor() : null;
    });

  const toneGenerator = toneGeneratorFactory({
    context: () => context!,
    destination: () => masterGain!,
  });

  function resumeIfArmed(): void {
    if (context && gate.armed() && context.state === 'suspended') {
      void (context as AudioContext).resume().then(
        () => status.set('running'),
        () => undefined,
      );
    }
  }

  function ensureContext(): BaseAudioContext | null {
    if (context) {
      return context;
    }
    const created = contextFactory();
    if (!created) {
      status.set('unsupported');
      return null;
    }
    context = created;
    masterGain = created.createGain();
    masterGain.gain.value = volume();
    masterGain.connect(created.destination);
    status.set(created.state as AudioStatus);
    resumeIfArmed();
    return context;
  }

  function blocked(): boolean {
    return muted() || (config.respectReducedMotion && reducedMotion()) || !gate.armed();
  }

  // Volume is communicated to the master node reactively — the single writer is
  // setVolume(), but binding through an effect keeps the node in sync from any
  // future volume source too.
  effect(() => {
    const v = volume();
    if (masterGain) {
      masterGain.gain.value = v;
    }
  });

  // Suspend on tab hide (frees the audio hardware); resume on return if armed.
  const onVisibility = (): void => {
    if (!context) {
      return;
    }
    if (doc.hidden) {
      if (context.state === 'running') {
        void (context as AudioContext).suspend().then(
          () => status.set('suspended'),
          () => undefined,
        );
      }
    } else {
      resumeIfArmed();
    }
  };
  doc.addEventListener('visibilitychange', onVisibility);
  destroyRef.onDestroy(() => {
    doc.removeEventListener('visibilitychange', onVisibility);
    // close() rejects on an already-closed context; swallow it so a double
    // destroy does not surface an unhandled rejection.
    const closing = (context as AudioContext | null)?.close?.();
    void closing?.then(
      () => undefined,
      () => undefined,
    );
  });

  return {
    play(name, scale) {
      if (blocked()) {
        return;
      }
      if (!ensureContext()) {
        return;
      }
      resumeIfArmed();
      if (!debouncer.shouldFire(name)) {
        return;
      }
      const earcon = earcons.get(name);
      if (!earcon) {
        if (isDevMode()) {
          console.warn(
            `[cngxAudio] Unknown earcon "${name}". Register it via withEarcons({...}) or engine.register(name, config).`,
          );
        }
        return;
      }
      toneGenerator.sequence(scaleSteps(earcon.sequence, scale));
      lastPlayed.set(name);
    },
    tone(freq, durationMs, opts, scale) {
      if (blocked() || !ensureContext()) {
        return;
      }
      resumeIfArmed();
      toneGenerator.tone(
        freq,
        durationMs,
        scale === undefined ? opts : { ...opts, gain: scaleGain(opts?.gain, scale) },
      );
    },
    sequence(steps, scale) {
      if (blocked() || !ensureContext()) {
        return;
      }
      resumeIfArmed();
      toneGenerator.sequence(scaleSteps(steps, scale));
    },
    register(name, earconConfig) {
      earcons.set(name, earconConfig);
    },
    armAutoplay() {
      gate.arm();
      resumeIfArmed();
    },
    setMuted(next) {
      muted.set(next);
    },
    setVolume(next) {
      volume.set(clampVolume(next));
    },
    muted: muted.asReadonly(),
    volume: volume.asReadonly(),
    status: status.asReadonly(),
    lastPlayed: lastPlayed.asReadonly(),
  };
}

interactive/menu/menu-radio-controller.ts

createMenuRadioController#CngxMenuRadioGroupFactory

Pure factory wiring a CngxMenuRadioGroup from already-created signals. CngxMenuGroup implements the contract directly; this factory exists for hand-built menu hosts that do not declare a directive but still need to provide CNGX_MENU_RADIO_GROUP.

({ selectedValue, name }) => ({
  selectedValue,
  name,
  select(value) {
    selectedValue.set(value);
  },
})

paginator/segments/paginator-page-window.token.ts

createPaginatorPageWindow#CngxPaginatorPageWindowFactory

Default page-window factory. Resolves to the built-in pageWindow math (one sibling each side, one pinned boundary at each end at the 1 / 1 defaults). The segment builds its window via inject(CNGX_PAGINATOR_PAGE_WINDOW_FACTORY)() rather than calling this directly, mirroring createPaginatorAnnouncer.

() => pageWindow

input/mask-presets/date-formats.ts

DATE_SHORT_FORMATS#Record
{
  'de-DE': '00.00.00',
  'de-AT': '00.00.00',
  'de-CH': '00.00.00',
  'fr-FR': '00/00/00',
  'fr-BE': '00/00/00',
  'fr-CH': '00.00.00',
  'fr-CA': '00-00-00',
  'es-ES': '00/00/00',
  'es-MX': '00/00/00',
  'es-AR': '00/00/00',
  'it-IT': '00/00/00',
  'it-CH': '00.00.00',
  'pt-PT': '00/00/00',
  'pt-BR': '00/00/00',
  'nl-NL': '00-00-00',
  'nl-BE': '00/00/00',
  'ru-RU': '00.00.00',
  'ja-JP': '00/00/00',
  'zh-CN': '00-00-00',
  'zh-TW': '00/00/00',
  'zh-HK': '00/00/00',
  'ko-KR': '00.00.00',
  'en-US': '00/00/00',
  'en-GB': '00/00/00',
  'en-AU': '00/00/00',
  'en-CA': '00-00-00',
  'en-IE': '00/00/00',
  'pl-PL': '00.00.00',
  'cs-CZ': '00.00.00',
  'sk-SK': '00.00.00',
  'hu-HU': '00.00.00',
  'ro-RO': '00.00.00',
  'bg-BG': '00.00.00',
  'el-GR': '00/00/00',
  'sv-SE': '00-00-00',
  'nb-NO': '00.00.00',
  'da-DK': '00-00-00',
  'fi-FI': '00.00.00',
  'hr-HR': '00.00.00',
  'sr-RS': '00.00.00',
  'sl-SI': '00.00.00',
  'uk-UA': '00.00.00',
  'lt-LT': '00-00-00',
  'lv-LV': '00.00.00',
  'et-EE': '00.00.00',
  'is-IS': '00.00.00',
  'mt-MT': '00/00/00',
  'ga-IE': '00/00/00',
  'lb-LU': '00.00.00',
  'tr-TR': '00.00.00',
}

interactive/breadcrumb/breadcrumb-responsive.ts

DEFAULT_BREADCRUMB_WIDTH_TIERS#CngxBreadcrumbWidthTier[]

Default width tiers, matching the headless responsive-collapse recipe: 640px and up shows 6, 440px and up shows 4, anything narrower shows 2. The 0 floor guarantees a match for every non-negative width.

[
  { minWidth: 640, maxVisible: 6 },
  { minWidth: 440, maxVisible: 4 },
  { minWidth: 0, maxVisible: 2 },
]

forms/field/form-field.token.ts

DEFAULT_HINT_FORMATTERS#ConstraintHintFormatters

English default formatters for constraint hints.

{
  lengthRange: (min, max) => `${min}–${max} characters`,
  minLength: (min) => `Min. ${min} characters`,
  maxLength: (max) => `Max. ${max} characters`,
  valueRange: (min, max) => `${min}–${max}`,
  minValue: (min) => `Min. ${min}`,
  maxValue: (max) => `Max. ${max}`,
  extra: () => [],
}

forms/input/input-config.ts

DEFAULT_INPUT_ARIA_LABELS#InputAriaLabels

English default ARIA labels for @cngx/forms/input. Directives read a key as config.ariaLabels?.<key> ?? DEFAULT_INPUT_ARIA_LABELS.<key>.

{
  clear: 'Clear',
  otpGroup: 'One-time code',
  otpSlot: (index, length) => `Digit ${index + 1} of ${length}`,
  otpComplete: 'Code complete',
  copySuccess: 'Copied',
  copyError: 'Copy failed',
  fileDropZone: 'File drop zone',
  capsLockOn: 'Caps Lock is on',
  passwordStrength: (label) => `Password strength: ${label}`,
  inputRejected: 'Character not allowed',
  sensitiveReveal: 'Value revealed',
  sensitiveHide: 'Value hidden',
  ratingValue: (value, max) => `${value} of ${max}`,
  ratingItem: (step, max) => `${step} of ${max}`,
  phoneCountry: 'Country',
}

interactive/menu/menu-config.ts

DEFAULT_MENU_CONFIG#CngxMenuConfig

Library-default menu configuration. English-only - German (or any other locale) is consumer-supplied via withAriaLabels per the feedback_en_default_locale rule.

{
  ariaLabels: {
    submenuOpened: 'Submenu opened',
    submenuClosed: 'Submenu closed',
    itemActivated: 'Item activated',
    itemDisabled: 'Item disabled',
    menuDismissed: 'Menu dismissed',
  },
  typeaheadDebounce: 300,
  submenuOpenDelay: 0,
  submenuCloseDelay: 150,
  closeOnSelect: true,
  dismissOnOutsideClick: true,
  dismissOnScroll: false,
  dismissOnBlur: true,
}

forms/filter-builder/filter-builder.types.ts

DEFAULT_OPERATORS#unknown

Default operator lists per builtin editor type. Consumers extend via withDefaultOperators({...}).

{
  string: ['contains', 'eq', 'neq', 'startsWith', 'endsWith', 'isEmpty', 'isNotEmpty'],
  number: ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'isEmpty', 'isNotEmpty'],
  date: ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'isEmpty', 'isNotEmpty'],
  boolean: ['eq', 'neq'],
} as const satisfies Record<FilterEditorType, readonly string[]>

tabs/scroll-sync/organism-scroll-sync.ts

DEFAULT_SCROLL_OPTIONS#ScrollIntoViewOptions
{
  behavior: 'smooth',
  block: 'nearest',
  inline: 'center',
}

audio/debouncer/debouncer.ts

DEFAULT_WINDOW_MS#number

Default suppression window in milliseconds.

100

ui/mat-paginator/mat-paginator-bridge.directive.ts

defaultAnnounceLabel#unknown

English default announcement. Localise via [announceLabel].

(c: CngxMatPaginatorAnnounceContext): string =>
`Page ${c.page} of ${c.totalPages}, showing items ${c.start} to ${c.end} of ${c.total}`

data/async-state/operators.ts

DOWNLOAD_PROGRESS#number
3
RESPONSE#number
4
UPLOAD_PROGRESS#number
1

common/stepper/create-stepper-host-proxy.ts

EMPTY_NODES#CngxStepNode[]
Object.freeze([])

data/recycler/range-computer.ts

EMPTY_RANGE#RangeResult
{
  start: 0,
  end: 0,
  offsetBefore: 0,
  offsetAfter: 0,
  totalSize: 0,
}

display/password-strength-meter/password-strength-meter.component.ts

filledEqual#unknown
(a: readonly boolean[], b: readonly boolean[]): boolean =>
a.length === b.length && a.every((v, i) => v === b[i])
SEGMENT_COUNT#number
4
STRENGTH_LEVELS#unknown
['none', 'weak', 'fair', 'good', 'strong'] as const

ui/layout/stack.component.ts

GAP_DEFAULTS#Record
{
  none: '0',
  xs: 'var(--cngx-gap-xs, 4px)',
  sm: 'var(--cngx-gap-sm, 8px)',
  md: 'var(--cngx-gap-md, 16px)',
  lg: 'var(--cngx-gap-lg, 24px)',
  xl: 'var(--cngx-gap-xl, 32px)',
}

audio/autoplay-gate/autoplay-gate.ts

GESTURE_EVENTS#unknown

The user-gesture events that satisfy the browser autoplay policy.

['pointerdown', 'keydown', 'touchstart'] as const

paginator/segments/paginator-dots.component.ts

HALF#unknown

Pages flanking the centred current page inside the viewport.

Math.floor(VISIBLE / 2)
VISIBLE#number

Visible dot count in the viewport before the track scrolls.

7

input/mask-presets/iban-patterns.ts

IBAN_PATTERNS#Record

IBAN format masks per country (ISO 3166-1 alpha-2 keys). A = letter, 0 = digit.

Source: official IBAN registry (SWIFT/ISO 13616). Unlike phone numbers, IBAN lengths are FIXED and officially standardised, so these masks are actually reliable, not approximations. IBAN is used in ~70 countries (mostly Europe + parts of the Middle East), hence no US/JP/CN/KR entries.

{
  // DACH
  CH: 'AA00 0000 0000 0000 0000 0', // 21
  DE: 'AA00 0000 0000 0000 0000 00', // 22
  AT: 'AA00 0000 0000 0000 0000', // 20
  // Western Europe
  FR: 'AA00 0000 0000 0000 0000 0000 000', // 27
  BE: 'AA00 0000 0000 0000', // 16, BBAN fully numeric
  NL: 'AA00 AAAA 0000 0000 00', // 18
  LU: 'AA00 0000 0000 0000 0000', // 20
  IE: 'AA00 AAAA 0000 0000 0000 00', // 22, 4-letter bank code + 14 digits
  GB: 'AA00 AAAA 0000 0000 0000 00', // 22
  MT: 'AA00 AAAA 0000 0000 0000 0000 000', // 31, longest IBAN in Europe
  // Southern Europe
  ES: 'AA00 0000 0000 0000 0000 0000', // 24
  IT: 'AA00 A000 0000 0000 0000 0000 000', // 27, 1 letter (CIN check char) at BBAN start
  PT: 'AA00 0000 0000 0000 0000 0000 0', // 25
  GR: 'AA00 0000 0000 0000 0000 0000 000', // 27
  // Northern Europe
  SE: 'AA00 0000 0000 0000 0000 0000', // 24
  NO: 'AA00 0000 0000 000', // 15, shortest in Europe
  DK: 'AA00 0000 0000 0000 00', // 18
  FI: 'AA00 0000 0000 0000 00', // 18
  IS: 'AA00 0000 0000 0000 0000 0000 00', // 26
  // Central Europe
  PL: 'AA00 0000 0000 0000 0000 0000 0000', // 28, fully numeric BBAN
  CZ: 'AA00 0000 0000 0000 0000 0000', // 24
  SK: 'AA00 0000 0000 0000 0000 0000', // 24
  HU: 'AA00 0000 0000 0000 0000 0000 0000', // 28
  // Eastern Europe / Balkans
  RO: 'AA00 AAAA 0000 0000 0000 0000', // 24, account part is alphanumeric
  BG: 'AA00 AAAA 0000 0000 0000 00', // 22
  HR: 'AA00 0000 0000 0000 0000 0', // 21
  RS: 'AA00 0000 0000 0000 0000 00', // 22
  SI: 'AA00 0000 0000 0000 000', // 19
  UA: 'AA00 0000 0000 0000 0000 0000 0000 0', // 29
  LT: 'AA00 0000 0000 0000 0000', // 20
  LV: 'AA00 AAAA 0000 0000 0000 0', // 21
  EE: 'AA00 0000 0000 0000 0000', // 20
  RU: 'AA00 0000 0000 0000 0000 0000 00', // 33, in the IBAN registry since 2021
  TR: 'AA00 0000 0000 0000 0000 0000 00', // 26, 1 reserved digit after the bank code
}

display/stat/stat.component.ts

idsEqual#unknown

Structural equality so an unchanged id set never cascades labelledBy.

(a: readonly string[], b: readonly string[]): boolean =>
a.length === b.length && a.every((id, i) => id === b[i])

Fixed reading order for the coordinated slots.

['label', 'value', 'delta', 'caption']

mat-tabs/material-bridge/private-surfaces.ts

MAT_MDC_TAB_HEADER_SELECTOR#string

.mat-mdc-tab-header — the strip element rendered by MatTabHeader. [cngxMatTabs] walks host.querySelector('.mat-mdc-tab-header') to locate the mount anchor for the cngx overflow molecule (so the More button pins inside Material's strip rather than as a sibling of <mat-tab-group>).

'.mat-mdc-tab-header'
MAT_MDC_TAB_LABEL_CONTAINER_SELECTOR#string

.mat-mdc-tab-label-container — Material's IO-friendly scroll viewport ancestor of the rendered tab buttons. The Material- twin overflow adapter walks host → header → any tab → closest label-container to attach the molecule's IntersectionObserver against the same element Material itself scrolls.

'.mat-mdc-tab-label-container'
MAT_MDC_TAB_SELECTOR#string

.mat-mdc-tab — the class Material applies to the rendered tab <button> elements inside MatTabHeader. cngx index-correlates presenter.tabs() registration order against host.querySelectorAll('.mat-mdc-tab') because MatTab is a portal — the rendered buttons live inside MatTabHeader's template, not on the <mat-tab> declaration site, and Material exposes no public per-tab element accessor.

'.mat-mdc-tab'

paginator/segments/paginator-nav.component.ts

select/shared/template-registry.ts

NO_ACTION_DIRECTIVE#Signal

Resolves the shared template slots through the 3-stage cascade. Injection context required (injectResolvedTemplate reads CNGX_SELECT_CONFIG).

signal(undefined)
NO_LOADING_GLYPH_DIRECTIVE#Signal
signal(undefined)

interactive/breadcrumb/breadcrumb-collapse.ts

NO_COLLAPSE#ReadonlySet
new Set()

ui/data-grid-accordion/data-grid-sort-header.directive.ts

NOT_SORTED#string
'not sorted, activate to sort ascending'
SORTED_ASCENDING#string
'sorted ascending, activate to sort descending'
SORTED_DESCENDING#string
'sorted descending, activate to sort ascending'

audio/pitch-mode/audio-pitch.directive.ts

PITCH_VOICE#string

Throttle key — the pitch directive plays a single ad-hoc voice.

'pitch'

display/time/time.component.ts

RELATIVE_DIVISIONS#literal type[]

Unit ladder for the relative formatter, smallest first. Each amount is the count of that unit in the next-larger one; anything past months falls through to the years return.

[
  { amount: 60, unit: 'seconds' },
  { amount: 60, unit: 'minutes' },
  { amount: 24, unit: 'hours' },
  { amount: 7, unit: 'days' },
  { amount: 4.34524, unit: 'weeks' },
  { amount: 12, unit: 'months' },
]

forms/input/password-strength.factory.ts

SCORE_LABELS#Record
{
  0: 'weak',
  1: 'weak',
  2: 'fair',
  3: 'good',
  4: 'strong',
}

display/segmented-progress/segmented-progress.component.ts

segmentsEqual#unknown
(a: readonly SegmentState[], b: readonly SegmentState[]): boolean =>
a.length === b.length && a.every((s, i) => s === b[i])

display/delta/delta.component.ts

SENTIMENT_WORD#Record
{
  positive: 'improved',
  negative: 'declined',
  neutral: 'unchanged',
}

forms/input/input-mask.directive.ts

SLOT_TOKENS#Record
{
  '0': { test: /[0-9]/, optional: false },
  '9': { test: /[0-9]/, optional: true },
  A: { test: /[a-zA-Z]/, optional: false },
  a: { test: /[a-zA-Z]/, optional: true },
  '*': { test: /[a-zA-Z0-9]/, optional: false },
}

common/stepper/stepper-config.ts

STEPPER_DEFAULT_DENSITY_BREAKPOINTS#CngxStepperDensityBreakpoints

Default per-step px thresholds for the density: 'auto' ladder. The literal lives on a single exported const so the runtime resolver, the config default, and any JSDoc cross-references stay in lockstep. Consumers override via withStepperDensity's second argument.

{
  compact: 120,
  minimal: 64,
}
STEPPER_DEFAULT_MOBILE_BREAKPOINT#string

Default media query the mobile auto-collapse policy reacts to. The literal lives on a single exported const so the runtime, the config default, and any JSDoc cross-references stay in lockstep. Consumers override the query via withStepperMobileBreakpoint.

'(max-width: 480px)'

common/tabs/tabs-config.ts

TABS_CONFIG_DEFAULTS#unknown
{
  defaultOrientation: 'horizontal',
  defaultLoop: true,
  defaultCommitMode: 'optimistic',
  fragmentSyncMode: 'fragment',
  fragmentSyncParam: 'tab',
  ariaLabels: {
    tabsRegion: 'Tabs',
  },
  fallbackLabels: {
    // W3C ARIA tablist convention - kept distinct from
    // `i18n.tabsLabel` so AT doesn't read the same string twice
    // back-to-back across `aria-roledescription` and `aria-label`.
    tabRoleDescription: 'tab list',
    tabPanelRoleDescription: 'tab panel',
  },
  overflowStabilizeMs: 100,
  overflowMaxDeferMs: 250,
  templates: {},
}
withDefaultOrientation#unknown
Use {@link withTabsDefaultOrientation}. The unprefixed name collides with the stepper family's identical symbol when both libs are auto-imported. The alias stays for one minor release before removal.
withTabsDefaultOrientation
withTabsRouterSync#unknown
Use {@link withTabsFragmentSync}. "Router sync" collided with the new `[cngxTabsRouteSync]` router-outlet directive; this feature only ever configured fragment / query-param deep-linking. The alias stays for one minor release before removal.
withTabsFragmentSync

tabs/i18n/tabs-i18n.ts

TABS_I18N_DEFAULTS#CngxTabsI18n
{
  tabsLabel: 'Tabs',
  selectedTab: (label, position, count) => `Tab ${position} of ${count}: ${label}`,
  tabLabelWithDetail: (label, detail) => `${label}, ${detail}`,
  tabHasErrors: (count) => `${count} error${count === 1 ? '' : 's'}`,
  moreTabsLabel: (count) => `${count} more`,
  previousTab: 'Previous tab',
  nextTab: 'Next tab',
  closeTab: (label) => `Close "${label}"`,
  addTab: 'Add tab',
  commitFailedRetry: 'Tab change refused — retry?',
  commitInFlight: 'Switching tab…',
  commitRolledBackTo: (originLabel) => `Could not save changes — reverted to "${originLabel}".`,
}

display/status/status.component.ts

TONE_GLYPH#Record

Tone glyph rendered inside the decorative dot - the non-colour signal.

{
  success: '✓',
  warning: '!',
  danger: '✕',
  info: 'i',
  neutral: '•',
}

interactive/menu/menu.directive.ts

warnedFocusHosts#unknown
new WeakSet<HTMLElement>()

input/mask-presets/zip-patterns.ts

ZIP_PATTERNS#Record

Postal-code format masks per country (ISO 3166-1 alpha-2 keys). A = letter, 0 = digit; a | declares length alternates picked by input length.

Note (like phone numbers): not every country has a strictly fixed format (Ireland's Eircode is highly irregular), so treat these as UI hints, not hard validators. Countries with no postal-code system (HK, AE, ...) are intentionally omitted - do not apply a zip: mask there.

{
  // DACH
  DE: '00000',
  AT: '0000',
  CH: '0000',
  // Western Europe
  FR: '00000',
  BE: '0000',
  NL: '0000 AA', // e.g. 1234 AB
  LU: '0000',
  IE: 'A00 0000', // Eircode since 2015; highly irregular
  GB: 'A0A 0AA|AA0 0AA|AA00 0AA|A0 0AA|A00 0AA|AA0A 0AA', // incl. AA0A 0AA (e.g. EC1A 1BB)
  UK: 'A0A 0AA|AA0 0AA|AA00 0AA|A0 0AA|A00 0AA|AA0A 0AA', // back-compat alias of GB
  MT: 'AAA 0000', // e.g. VLT 1117
  // Southern Europe
  ES: '00000',
  IT: '00000',
  PT: '0000-000',
  GR: '000 00',
  // Northern Europe
  SE: '000 00',
  NO: '0000',
  DK: '0000',
  FI: '00000',
  IS: '000', // 3-digit, very small system
  // Central Europe
  PL: '00-000',
  CZ: '000 00',
  SK: '000 00',
  HU: '0000',
  // Eastern Europe / Balkans
  RO: '000000',
  BG: '0000',
  HR: '00000',
  RS: '00000',
  SI: '0000',
  UA: '00000',
  LT: '00000', // often written with an "LT-" prefix
  LV: '0000', // often written with an "LV-" prefix
  EE: '00000',
  RU: '000000',
  TR: '00000',
  // North America
  US: '00000', // ZIP+4 (00000-0000) not modelled here
  CA: 'A0A 0A0', // alternating letter/digit
  MX: '00000',
  // East Asia
  JP: '000-0000',
  CN: '000000',
  KR: '00000', // 5-digit since 2015
  TW: '00000', // modern 5-digit (3+2)
  // Southeast Asia
  SG: '000000',
  MY: '00000',
  TH: '00000',
  VN: '000000',
  PH: '0000',
  ID: '00000',
  // South Asia
  IN: '000 000', // PIN code, also written without the space
  // Middle East
  IL: '0000000',
  SA: '00000-0000', // base 5-digit, "-0000" extension often omitted
  // Africa
  ZA: '0000',
  EG: '00000',
  NG: '000000',
  // Latin America
  AR: 'A0000AAA', // format since 1999 (e.g. C1425CKC); older 4-digit still seen
  CL: '0000000',
  CO: '000000',
  PE: '00000',
  BR: '00000-000',
  // Oceania
  AU: '0000',
  NZ: '0000',
}