Skip to content

@telixon/web-sdk

@telixon/web-sdk binds @telixon/core to the web platform: a phone input adapter, a region list controller, and a flag emoji helper. It ships no CSS and no image assets; rendering stays yours.

createPhoneInput and createRegionList require a ready engine and throw EngineNotReadyError otherwise; initialize with ensureEngineReady() from @telixon/core first.

function createPhoneInput(options: PhoneInputOptions): PhoneInput;

Attaches a headless phone input controller to a DOM <input> element. It wires the element’s native editing events (beforeinput, compositionend, undo/redo keyboard shortcuts) to a core input controller and keeps the value, caret, and resolved phone metadata in sync through every reformat.

Throws when the element is not type="text" or type="tel", when another PhoneInput is already attached to the same element, or when the engine is not ready.

import { ensureEngineReady } from '@telixon/core';
import { createPhoneInput } from '@telixon/web-sdk';
await ensureEngineReady();
const inputElement = document.querySelector('input');
if (!(inputElement instanceof HTMLInputElement)) throw new Error('input element not found');
const phoneInput = createPhoneInput({
mode: 'national',
input: inputElement,
defaultRegion: 'US',
});
phoneInput.subscribe((state) => {
// state: PhoneInputState
});

A discriminated union on mode: NationalPhoneInputOptions (mode: 'national') or InternationalPhoneInputOptions (mode: 'international'). Both share the base options:

Option Type Default Description
input PhoneInputElement required The <input> to attach; must be type="text" or type="tel".
initialValue string '' Seeds the first state, applied to the DOM at construction.
regionFilter readonly RegionCode[] | null null Restricts resolution to the given regions.
numberTypeFilter readonly NumberType[] | null null Restricts resolution to the given number types.
placeholderNumberType NumberType 'MOBILE' The number type whose example becomes state.placeholder.

Each mode adds its core controller configuration:

Mode Additional options
'national' defaultRegion (required), strict, maxHistorySize; see NationalInputControllerConfig.
'international' defaultRegion, strict, maxHistorySize, display; display.callingCodeInInput: false requires defaultRegion. See InternationalInputControllerConfig.

PhoneInputElement is HTMLInputElement.

The initial state is applied to the DOM at construction but not emitted to subscribers; call getState() after subscribe to read the bootstrap value.

Method Returns Description
subscribe(listener) () => void Subscribes to state changes; returns an unsubscribe function.
getState() PhoneInputState Reads the current state without subscribing.
setValue(value) void Replaces the current value as one parse-and-format operation. Pushes a history entry.
setRegion(region) void Switches the active region and re-resolves the digits. Pushes a history entry.
undo(), redo() void History navigation; no-op when the matching availability check returns false.
canUndo(), canRedo() boolean History availability.
clearHistory() void Drops undo/redo history, keeping the current entry.
getPhoneNumber() PhoneNumber Builds a PhoneNumber from the current digits.
setRegionFilter(regions) void Restricts resolution to regions; null removes the restriction.
setNumberTypeFilter(numberTypes) void Restricts resolution to numberTypes; null removes the restriction.
destroy() void Detaches all DOM listeners and clears subscribers. Idempotent.

PhoneInputListener is (state: PhoneInputState) => void.

The snapshot emitted after every state change.

Field Type Description
value string The formatted value currently in the input.
region RegionCode | null The region resolved from the digits, or null when unresolved.
selectionStart, selectionEnd number The caret range within value after the last operation.
regionFilter readonly RegionCode[] | null The active region restriction; null means none.
numberTypeFilter readonly NumberType[] | null The active number type restriction; null means none.
placeholder string | null The example number for the resolved region and display config, or null when unresolved. Exposed in state only, never written to the element.
validationError ValidationError | null The structured outcome of getPhoneNumber().getValidationError(), or null when none apply.
function createRegionList<T = undefined>(options?: RegionListOptions<T>): RegionList<T>;

Creates a headless region list controller for pickers, dropdowns, and selector UIs: a reactive list of region options that is filtered, searched, sorted, prioritized, and localized as pure state. No DOM is involved.

On every change the pipeline runs in a fixed order: base set (cached per locale), then regionFilter, numberTypeFilter, search, sort, and prioritize. The generic T flows from the dataFactory return type; without a factory, data is present and undefined.

import { createRegionList } from '@telixon/web-sdk';
const regionList = createRegionList();
regionList.search('ukr');
regionList.getState().options;
// [{ region: 'UA', callingCode: '380', displayName: 'Ukraine', data: undefined }]

All fields are optional.

Option Type Default Description
dataFactory RegionDataFactory<T> none Produces the data slot for each option. Invoked once per region at construction and on localize/refresh; expected to be pure.
regionFilter readonly RegionCode[] | null null Restricts the list to the given regions. [] matches nothing.
numberTypeFilter readonly NumberType[] | null null Restricts the list to regions supporting at least one of the given number types. [] matches nothing.
searchQuery string '' Initial search query.
searchFn RegionSearchFn<T> built-in search Custom search predicate; see Search.
locale string 'en' Locale for display names and collation.
sort RegionListSort<T> 'alphabetical' Sort order; see Sort.
prioritize readonly RegionCode[] [] Regions pinned to the top of the sorted list, in the given order.

RegionDataFactory<T> is (input: RegionDataFactoryInput) => T; RegionDataFactoryInput carries the precomputed region, callingCode, displayName, and the active locale.

No emit fires on construction; call getState() after subscribe to read the bootstrap value. Action verbs (search, localize) name user-driven interactions; set* names declarative configuration changes.

Method Returns Description
subscribe(listener) () => void Subscribes to state changes; returns an unsubscribe function.
getState() RegionListState<T> Reads the current state without subscribing.
search(query) void Updates the query and re-runs the pipeline. No-op when unchanged.
localize(locale) void Switches the locale, recomputes display names and data, and re-runs the pipeline. No-op when unchanged.
refresh() void Recomputes the base set (display names and dataFactory) and re-emits. For when external state read by dataFactory changes. Always emits.
setRegionFilter(value) void Replaces the region restriction; null removes it, [] matches nothing. No-op when unchanged.
setNumberTypeFilter(value) void Replaces the number type restriction; null removes it, [] matches nothing. No-op when unchanged.
destroy() void Clears all subscribers. Idempotent.

RegionListListener<T> is (state: RegionListState<T>) => void.

One entry in the rendered list.

Field Type Description
region RegionCode Two-letter region code, for example 'US'.
callingCode string Calling code digits, for example '1'.
displayName string Region name from Intl.DisplayNames for the active locale; falls back to the region code when the runtime cannot produce a localized name. The exact string depends on the runtime’s ICU data.
data T The dataFactory result; undefined without a factory.
import { createRegionList, regionToFlagEmoji } from '@telixon/web-sdk';
const regionList = createRegionList({
dataFactory: ({ region }) => ({ flag: regionToFlagEmoji(region) }),
});
regionList.getState().options.find((option) => option.region === 'UA');
// { region: 'UA', callingCode: '380', displayName: 'Ukraine', data: { flag: '🇺🇦' } }

The built-in search matches case-insensitively and diacritic-insensitively against the display name, the region code, and the calling code. The calling code match is a substring match, and a leading + in the query is accepted. Empty and whitespace-only queries short-circuit to the full list without invoking the search function.

const regionList = createRegionList();
regionList.search('+38');
regionList.getState().options.map((option) => option.region);
// ['BA', 'CV', 'HR', 'XK', 'ME', 'MK', 'RS', 'SI', 'UA']

RegionSearchFn<T> is (query: string, option: RegionOption<T>) => boolean: return true to include option. It receives the raw query and performs its own normalization.

RegionListSort<T> selects the comparator:

Value Order
'alphabetical' By displayName collated in the list’s locale, then region code. Default.
'callingCode' By numeric calling code, then displayName, then region code.
comparator (a: RegionOption<T>, b: RegionOption<T>) => number; you own its ordering.

The built-in comparators break ties by region code, so they are total orders: a given runtime always produces the same order. Display names and collation come from the runtime’s ICU, so the order can differ between environments.

const regionList = createRegionList({
sort: 'callingCode',
prioritize: ['US', 'GB'],
});
regionList
.getState()
.options.slice(0, 5)
.map((option) => `${option.region} +${option.callingCode}`);
// ['US +1', 'GB +44', 'AS +1', 'AI +1', 'AG +1']

The snapshot emitted on every state change.

Field Type Description
options readonly RegionOption<T>[] The post-filter, post-sort, post-prioritize list as currently rendered.
regionFilter readonly RegionCode[] | null The active region restriction; null means none.
numberTypeFilter readonly NumberType[] | null The active number type restriction; null means none.
searchQuery string The active query.
locale string The active locale.
function regionToFlagEmoji(region: RegionCode): string;

Converts a region code to its flag emoji: the two Unicode regional indicator symbols for its letters, derived arithmetically. No image assets are involved. Rendering is the platform’s choice: systems with flag emoji support show a flag; systems without it (notably Windows) show the two letters. For a flag on every platform, render an SVG set keyed by the region code instead.

import { regionToFlagEmoji } from '@telixon/web-sdk';
regionToFlagEmoji('UA'); // '🇺🇦'
regionToFlagEmoji('CH'); // '🇨🇭'

Every type-only export and where this page documents it:

Type Documented in
PhoneInputOptions, NationalPhoneInputOptions, InternationalPhoneInputOptions, PhoneInputElement PhoneInputOptions
PhoneInput, PhoneInputListener PhoneInput
PhoneInputState PhoneInputState
RegionListOptions, RegionDataFactory, RegionDataFactoryInput RegionListOptions
RegionList, RegionListListener RegionList
RegionOption RegionOption
RegionSearchFn Search
RegionListSort Sort
RegionListState RegionListState