# Ellipsis center

- Entry point: `@koobiq/components/ellipsis-center`
- NgModule: `KbqEllipsisCenterModule`
- Page: https://koobiq.io/en/components/ellipsis-center/overview

## Overview

Ellipsis Center truncates long single-line text in the middle so that its beginning and end remain visible within the available width.

### Usage

Pass the text to the `kbqEllipsisCenter` input of an element whose width is limited by its container. The directive renders the text itself, so leave the element empty.

```html
<div [kbqEllipsisCenter]="file.name"></div>
```

### Behavior

- When the text does not fit, the directive keeps its end visible — a file extension or the digits that tell two reports apart — and puts the ellipsis in the middle.
- A [tooltip](https://koobiq.io/en/components/tooltip.md) with the full text appears only while part of the text is hidden. Set `kbqTooltipDisabled` to turn it off.
- Text shorter than `minVisibleLength` is not split and is truncated at the end.
- The split is recalculated when the element is resized, including resizes that leave the window size unchanged, such as dragging a splitter. `debounceInterval` sets the delay in milliseconds, 50 by default.

The directive shows file names in [File upload](https://koobiq.io/en/components/file-upload.md) and long items in [Breadcrumbs](https://koobiq.io/en/components/breadcrumbs.md).

## API

### Directives

#### KbqEllipsisCenterDirective (directive)

Renders text as two spans and moves the ellipsis into the middle, so the tail — a file extension, the
digits that tell two reports apart — stays readable when the host is too narrow for the whole string. A
tooltip spells out the full text, and is enabled only while something is actually hidden.

The tooltip's `forDisabledComponent` is not for this host and should not be bound on it: the hint always
repeats the text this directive shortened, never an explanation of why a wrapped control is unavailable,
and the two derive the same state, so they would overwrite each other. Overflow is the only state the
directive derives, and `kbqTooltipDisabled` is how a consumer suppresses the hint.

```ts
@Directive({ selector: '[kbqEllipsisCenter]' })
class KbqEllipsisCenterDirective extends KbqTooltipTrigger {
    readonly ignoreTooltipPointerEvents = input<boolean>(true);
    readonly minVisibleLength = input<number>(0);
    readonly charWidth = input<number>(7);
    readonly debounceInterval = input<number>(50);
    readonly forDisabledComponent = input<Record<'disabledSignal', WritableSignal<boolean>>>();
    readonly singleInstance = input<boolean>(
        inject(KBQ_TOOLTIP_SINGLE_INSTANCE_DEFAULT),
        { alias: 'kbqTooltipSingleInstance' }
    );
    hideWithTimeout = input<boolean | undefined>();
    set kbqEllipsisCenter(value: string);
    tooltipVisible: boolean;
    tooltipPlacement: KbqPopUpPlacementValues;
    relativeToPointer: boolean;
    relativeToCaret: boolean;
    relativeToCaretVertical: KbqCaretVerticalAnchor;
    tooltipPlacementPriority: string | string[] | null;
    content: string | TemplateRef<unknown>;
    disabled: boolean;
    enterDelay: number;
    leaveDelay: number;
    trigger: string;
    customClass: string;
    context: unknown;
    color: KbqComponentColors | string;
    arrow: boolean;
    offset: number | null;
    readonly placementChange: EventEmitter<KbqPopUpPlacementValues>;
    readonly visibleChange: EventEmitter<boolean>;
    modifier: KbqEnumValues<TooltipModifier>;
    header: string | TemplateRef<unknown>;
    isOpen: boolean;
    get isAttached(): boolean;
    get openedChange(): Observable<boolean>;
    show(delay?: number): void;
    hide(delay?: number): void;
    showForMouseEvent(event: MouseEvent): void;
    showForElement(element: HTMLElement): void;
    updateOrigin(origin: KbqOverlayOrigin | null): void;
}
```

- `[ignoreTooltipPointerEvents]`: `boolean` — Overrides the tooltip's hoverable default, as `KbqOptionTooltip` does. The hint spells out text that
  the directive had to truncate, so it floats over the neighbouring content — and a pointer-capturing
  pane would swallow the clicks meant for it.
- `[minVisibleLength]`: `number` — Shortest text worth splitting in the middle. Anything below it keeps its natural order and is cut off
  at the end by the host's own `text-overflow`.

  Defaults to `0` — every overflowing text is split — because that is what the directive has always
  done: the input was declared but never read, so any other default would silently end-truncate labels
  that consumers expect to see split.
- `[charWidth]`: `number` — Lower bound, in pixels, for the average glyph width used to decide how many characters fit in the
  tail. The rendered text is measured as well and the wider of the two wins, so an underestimate here
  can no longer push the extension out of the tail — raising it only shortens the tail further.
- `[debounceInterval]`: `number` — Debounce time (ms) for resize events before recalculating ellipsis position. Defaults to `50`.
- `[forDisabledComponent]`: `Record<'disabledSignal', WritableSignal<boolean>>` — Input for controlling the disabled state of a component.

  The input expects a component containing `disabledSignal` property, which is
  a writable signal emitting boolean values.
- `[kbqTooltipSingleInstance]`: `boolean` — Whether the tooltip takes part in the "only one tooltip is visible at a time" group: showing it
  hides the previously visible tooltip, and it is hidden when another tooltip is shown.

  Defaults to `true`; the default can be changed application-wide with the
  `KBQ_TOOLTIP_SINGLE_INSTANCE_DEFAULT` token.

  Tooltips without an interactive `kbqTrigger` (`manual`, `none`, …) never take part in the group,
  regardless of this input — they are shown imperatively and are expected to stay pinned.
- `[hideWithTimeout]`: `boolean | undefined` — Changes hiding behavior. By default, tooltip is hidden on mouseleave from trigger.
  Setting hideWithTimeout to true will delay tooltip hiding and will not hide when the mouse moves from trigger
  to tooltip.
- `tooltipVisible`: `boolean` — Input (`kbqVisible`) that programmatically shows or hides the tooltip; reflects the current `visible` state.
- `tooltipPlacement`: `KbqPopUpPlacementValues` — Input (`kbqPlacement`) that sets the tooltip placement relative to its trigger; reflects the current `placement`.
- `relativeToPointer`: `boolean` — Positions the tooltip relative to the mouse cursor. Only available for top and bottom kbqPlacement.
  Does not work with kbqPlacementPriority.
- `relativeToCaret`: `boolean` — Positions the tooltip relative to the text caret of the field it is attached to, following it while the
  user types, moves the caret and scrolls the field. Anchors to the selection whenever there is one.

  Every placement is available, unlike with `kbqRelativeToPointer`: the caret is anchored as a rectangle,
  so the usual fallback placements keep the tooltip on screen. Wins when both inputs are enabled.

  The field is the host element itself when it is editable, otherwise the first editable it wraps.
- `relativeToCaretVertical`: `KbqCaretVerticalAnchor` — What the tooltip is vertically anchored to while `kbqRelativeToCaret` is enabled.
- `tooltipPlacementPriority`: `string | string[] | null` — Input (`kbqPlacementPriority`) that sets the ordered fallback placements; reflects the current `placementPriority`.
- `content`: `string | TemplateRef<unknown>` — Input (`kbqTooltip`) with the tooltip content — a string or a template. Updating it refreshes an open tooltip.
- `disabled`: `boolean` — Input (`kbqTooltipDisabled`) controlling whether the tooltip is disabled; setting it to `true` hides it.
  `undefined` leaves the decision to the trigger, like an unset input.

  Reads back the *effective* state, which for triggers that derive one of their own (see
  `derivedDisabledWins`) is not necessarily the value that was written.
- `enterDelay`: `number` — Input (`kbqEnterDelay`) — delay in milliseconds before the tooltip is shown. Defaults to `400`.
- `leaveDelay`: `number` — Input (`kbqLeaveDelay`) — delay in milliseconds before the tooltip is hidden. Defaults to `0`.
- `trigger`: `string` — Input (`kbqTrigger`) with the comma-separated trigger events. An empty value resets to hover + focus and rebinds listeners.
- `customClass`: `string` — Input (`kbqTooltipClass`) with an extra CSS class applied to the tooltip; updating it refreshes the class map.
- `context`: `unknown` — Input (`kbqTooltipContext`) with the context object passed to a template tooltip; updating it refreshes the open tooltip.
- `color`: `KbqComponentColors | string` — Input (`kbqTooltipColor`) with the tooltip color theme. Defaults to `KbqComponentColors.Contrast`.
- `arrow`: `boolean` — Input (`kbqTooltipArrow`) — whether to render the tooltip's arrow/pointer. Defaults to `false`.
- `offset`: `number | null` — Input (`kbqTooltipOffset`) — distance in pixels between the tooltip and its trigger. `null`, the default, keeps
  the gap of the stylesheet.
- `placementChange`: `EventEmitter<KbqPopUpPlacementValues>` — Output (`kbqPlacementChange`) that emits the new placement whenever the tooltip repositions.
- `visibleChange`: `EventEmitter<boolean>` — Output (`kbqVisibleChange`) that emits when the tooltip's visibility changes.
- `modifier`: `KbqEnumValues<TooltipModifier>` — Visual variant of the tooltip. Accepts `'default'` | `'warning'` | `'extended'`.
  Replaces the removed `KbqWarningTooltipTrigger` and `KbqExtendedTooltipTrigger`
  subclasses — to render a warning tooltip use `kbqTooltipModifier="warning"`,
  and `kbqTooltipModifier="extended"` for the extended variant (combine with `kbqTooltipHeader`).
- `header`: `string | TemplateRef<unknown>` — Header text or template, rendered above the tooltip content. Only meaningful with
  `kbqTooltipModifier="extended"`. Replaces the removed `KbqExtendedTooltipTrigger.header`.
- `isOpen`: `boolean` — Whether the pop-up overlay is currently open.
- `isAttached`: `boolean` — Whether the pop-up overlay is currently attached.

  Unlike `isOpen`, which follows the visibility of the pop-up component and therefore lags a task behind
  `show()`/`hide()`, this flips synchronously — it is the window during which the overlay (and its
  backdrop) is present in the DOM. Part of the `KbqSiblingPopup` contract.
- `openedChange`: `Observable<boolean>` — Emits `true` when the pop-up opens and `false` when it closes. Part of the `KbqSiblingPopup` contract.
- `show()`: `void` — Shows the tooltip after `delay` ms. Suppresses showing while a pop-up on the same element holds the
  anchor or on a focus trigger that did not originate from the keyboard, and applies cursor-relative
  positioning when `relativeToPointer` is enabled.
- `hide()`: `void` — Hides the tooltip after `delay` ms and, when the user has genuinely left the host, un-mutes a tooltip
  that a pop-up on the same element had muted.

  `mouseleave` and `blur` are the release signals because the base class binds `hide` to both regardless
  of whether the tooltip is currently visible. A pop-up that is still attached does not count: its
  backdrop steals the hover from the trigger while the pointer stands still, and that `mouseleave` must
  not be mistaken for the user leaving.
- `showForMouseEvent()`: `void` — Shows the tooltip next to the cursor position of the given mouse event, anchoring it to the event's
  `currentTarget` instead of the directive's own host element.

  Use it when the trigger cannot be declared in the template — for instance for a tooltip shared by the
  cells of a virtualized table. The directive still has to be created in an injection context.
- `showForElement()`: `void` — Shows the tooltip anchored to the given element instead of the directive's own host element.

  Use it when the trigger cannot be declared in the template. The directive still has to be created in an
  injection context:

  ```ts
  const tooltip = runInInjectionContext(injector, () => new KbqTooltipTrigger());
  tooltip.showForElement(element);
  ```

  Does nothing while the tooltip is disabled or has no content — there is no overlay to anchor then.
- `updateOrigin()`: `void` — Positions the pop-up against `origin` — an element, or a rectangle in viewport coordinates such as the one
  `kbqCreateCaretOrigin` keeps on the caret — instead of the host element; `null` restores the host
  element. An open pop-up moves to the new origin at once.

  This moves the position origin only. `setExternalNativeElement` moves the host itself, and with it
  the trigger's event listeners, its focus target and the scroll containers the pop-up follows.
