Skip to content

cartoonclouds/phone-normaliser

Repository files navigation

@cartoonclouds/phone-normaliser

A multi-region phone number normalisation toolkit for Vue 3 and standalone usage. The package builds on top of libphonenumber-js to deliver:

  • 🔄 Normalisation – converts messy, localised strings into consistent E.164 / international / national outputs.
  • Validation – configurable checks for blocklists, country allow-lists, length constraints, and extension policies.
  • 🧠 Region fallback logic – automatic detection with graceful degradation through default + fallback country lists.
  • 🧩 Vue bindings – composable + directive for instant drop-in formatting within apps.
  • 🧪 TypeScript-first – shared types for options, blocklists, and result shapes.

Installation

npm install @cartoonclouds/phone-normaliser

Quick Start

Normalise a phone number

import { normalisePhone } from '@cartoonclouds/phone-normaliser'

const result = normalisePhone('+44 (0) 7700 900123 ext 9', {
  defaultCountry: 'GB',
  format: 'INTERNATIONAL',
})

console.log(result.phone)          // +44 7700 900123
console.log(result.metadata.e164)  // +447700900123
console.log(result.changes)        // ['Converted unicode digits and separators.', 'Removed phone extension text.']

Validate a phone number

import { validatePhone, PhoneValidationCodes } from '@cartoonclouds/phone-normaliser'

const checks = validatePhone('555 123', {
  defaultCountry: 'US',
  minLength: 10,
})

checks.forEach((check) => {
  if (check.validationCode !== PhoneValidationCodes.VALID) {
    console.warn(check.validationMessage)
  }
})

Vue composable

<script setup lang="ts">
import { usePhone } from '@cartoonclouds/phone-normaliser'

const { value, phone, valid, changes, apply } = usePhone('', {
  autoFormat: true,
  defaultCountry: 'US',
})
</script>

<template>
  <label class="flow">
    <span>Phone</span>
    <input v-model="value" placeholder="Enter phone" />
    <p v-if="!valid">{{ changes.join(', ') }}</p>
    <button @click="apply">Apply formatted number</button>
    <output>{{ phone }}</output>
  </label>
</template>

Vue directive

<template>
  <input
    v-phone="{
      autoFormat: true,
      defaultCountry: 'KE',
      previewSelector: '#phone-preview'
    }"
    placeholder="Enter phone"
  />
  <div id="phone-preview"></div>
</template>

The directive emits a directive:phone:normalised event when validation fails so forms can react immediately.

Browser Support

The published bundles target ES2018 syntax and ship ESM + CJS builds that align with the browserslist query >0.3%, last 2 versions, Firefox ESR, not dead. In practice that covers the latest Chrome, Edge, Firefox (stable + ESR) and Safari 14+ on macOS/iOS, along with their Android counterparts. The Vue directive lazily accesses document, so it also plays nicely with SSR setups where the DOM is unavailable during server renders.

API Reference

normalisePhone(input, options?)

  • defaultCountry – ISO country code used when no international prefix exists.
  • fallbackCountries – ordered list used if parsing fails with the default.
  • allowedCountries – restrict valid countries.
  • blocklistPhoneBlockConfig to block numbers, prefixes, or countries.
  • format'E.164' | 'INTERNATIONAL' | 'NATIONAL' | 'RFC3966' (default: E.164).
  • stripExtensions – remove trailing extensions before parsing (default: true).
  • returns PhoneNormResult with parsed metadata and change codes.

validatePhone(input, options?)

Runs the same parsing logic but returns an array of ValidationResult objects with explicit PhoneValidationCodes covering:

  • Empty input detection
  • Invalid shape or length
  • Blocklists and country allow-lists
  • Extension policy breaches

resolvePhoneNumber(raw, config?)

Returns the underlying libphonenumber-js object without additional validation logic. Helpful if you only need to detect the country or format text yourself.

import { resolvePhoneNumber } from '@cartoonclouds/phone-normaliser'

const resolved = resolvePhoneNumber('07911 123456', {
  defaultCountry: 'GB',
  fallbackCountries: ['IE', 'US'],
})

if (resolved) {
  console.log(resolved.phoneNumber.number) // +447911123456
  console.log(resolved.usedFallback)       // 'GB'
}

usePhone(initialValue?, options?)

Vue 3 Options API-friendly composable returning { value, phone, valid, changes, apply, validate }.

PhoneDirective

Directive that formats inputs as you type. Options mirror normalisePhone plus autoFormat, autoFormatEvents, and previewSelector for mirrored output.

Development

Command Purpose
npm run build Bundle CJS/ESM outputs (with declarations) via tsdown.
npm run dev Watch and rebuild while hacking on src/ using tsdown.
npm run test / npm run test:watch Execute the full Vitest suite once or in watch mode.
npm run lint Apply ESLint autofixes.
npm run docs Regenerate the Typedoc markdown under docs/.

Documentation

The docs/ directory is generated by Typedoc and lists every exported type, helper, and constant. Run npm run docs after changing the public API so README snippets and generated reference stay aligned.

Testing

All utilities and bindings are covered by Vitest suites.

cd packages/phone-normaliser
npm run test

License

MIT © Cartoon Clouds

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published