@desource/phone-mask-react

中文文档
2.1.0发布于 2026/11/07MITTypeScriptESM + CJS构建来源已验证近 30 天下载 2万

QQ 反应组件和钩子用于国际电话号码输入,并带有智能口罩. 由@desource/phone-mask和Google libphone数字提供.

中文使用文档
文档目录29 节
  1. * 特性
  2. * 安装
  3. QQ 快速启动
  4. 导入
  5. 组件模式
  6. 钩子模式
  7. 发送 Raw 数字到后端
  8. 关于国家变化的动态遮罩更新
  9. 多租户:租户Id 默认国家+特定租户审定规则
  10. ++ 显示格式
  11. * 构件 API
  12. 道具
  13. 查找方法
  14. 胡克 API
  15. 选项
  16. 返回值
  17. 组件样式
  18. CSS 自定义属性
  19. 黑暗主题
  20. 实例
  21. 有验证
  22. 自动检测国家
  23. 带有窗体库
  24. 多个输入
  25. QQ 浏览器支持
  26. 包含什么
  27. 有关软件包
  28. 许可证
  29. 捐款

@ desource/ phone- mask- react

使用智能口罩和Google libphone数字数据进行电话输入组件和钩子

npm version code coverage SonarCloud Ask CodeWiki Ask Context7 Ask DeepWiki license

美丽,可访问,极小和可树可震动的电话回放输入,并带有自动格式化,国家选择器,以及验证功能.

升级到 2. 0. 0 之前,审查 1.7.0的移徙 用于断开更改和需要更新.

* 特性

  • 🌐 安保部门支助 —— 说 PhoneInput 在服务器上使 HTML 格式化,并在浏览器中使水合物格式化
  • 🎨 美丽的UI ——以轻/暗为主题的现代设计
  • 🔍 智能国家搜索 ——模糊匹配键盘导航
  • 🎭 自动格式化 ——有智能光标的现用类型格式
  • ✅ 验证 ——内设有视觉反馈的验证
  • 📋 复制按钮 — 一击副本到剪贴板
  • 🌐 自动检测 ——地生化和地生化探测
  • ♿ 可访问 ——ARIA标签,键盘导航
  • 📱 便于移动 - 优化触摸装置
  • 🎯 类型脚本 - 全套安全
  • 🪝 虎克 API - 用于自定义输入执行
  • ⚡ 优化 - 树摇和代码分割

粘贴一个完整的国际编号,从 + 检测其国家并替换全部输入. 检测尝试精确的口罩,然后呼叫代码和数字计数;共享匹配使用调用代码的默认国家. 它使用遮罩数据,而不是分配前缀,所以一个未格式化的加拿大人 +1 数字默认为美国. 没有呼叫代码的碎片保留了选定的国家,并粘贴在护身符上. 这能独立运作 detect,用于控制 GeoIP 和 locale 检测.

* 安装

npm install @desource/phone-mask-react
# or
yarn add @desource/phone-mask-react
# or
pnpm add @desource/phone-mask-react

QQ 快速启动

导入

组件模式 :

import { PhoneInput } from '@desource/phone-mask-react';
import '@desource/phone-mask-react/assets/lib.css'; // Import styles

钩模式 :

import { usePhoneMask } from '@desource/phone-mask-react';

从核心包子路径再出口的核心工具包和掩码数据:

import { getFlagEmoji, formatDigitsWithMap } from '@desource/phone-mask-react/core';

组件模式

import { useState } from 'react';
import { PhoneInput } from '@desource/phone-mask-react';
import '@desource/phone-mask-react/assets/lib.css'; // Import styles

function App() {
  const [phone, setPhone] = useState('');
  const [isValid, setIsValid] = useState(false);

  return (
    <>
      <PhoneInput value={phone} onChange={setPhone} onValidationChange={setIsValid} country="US" />

      {isValid && <p>✓ Valid phone number</p>}
    </>
  );
}

钩子模式

关于自定义输入执行:

import { useState } from 'react';
import { usePhoneMask } from '@desource/phone-mask-react';

function CustomPhoneInput() {
  const [value, setValue] = useState('');

  const { ref, digits, full, fullFormatted, isComplete, country, setCountry } = usePhoneMask({
    value,
    onChange: setValue,
    country: 'US',
    detect: true
  });

  return (
    <div>
      <input ref={ref} type="tel" placeholder="Phone number" />
      <p>Formatted: {fullFormatted}</p>
      <p>Valid: {isComplete ? 'Yes' : 'No'}</p>
      <p>Country: {country.name}</p>
      <button onClick={() => setCountry('GB')}>Use UK</button>
    </div>
  );
}

发送 Raw 数字到后端

import { useState } from 'react';
import { PhoneInput, type PMaskPhoneNumber } from '@desource/phone-mask-react';

function CheckoutForm() {
  const [digits, setDigits] = useState('');

  const handlePhoneChange = (phone: PMaskPhoneNumber) => {
    const payload = {
      phoneDigits: phone.digits, // unformatted, backend-friendly
      phoneFull: phone.full // optional full number with country code
    };

    setDigits(phone.digits);
    void fetch('/api/profile/phone', {
      method: 'POST',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify(payload)
    });
  };

  return <PhoneInput value={digits} onChange={setDigits} country="US" onPhoneChange={handlePhoneChange} />;
}

关于国家变化的动态遮罩更新

import { useMemo, useState } from 'react';
import { usePhoneMask, type PCountryKey } from '@desource/phone-mask-react';

function CountryAwareInput() {
  const [digits, setDigits] = useState('');
  const [country, setCountry] = useState<PCountryKey>('US');

  const {
    ref,
    fullFormatted,
    isComplete,
    setCountry: setMaskCountry
  } = usePhoneMask({
    value: digits,
    onChange: setDigits,
    country
  });

  const onCountrySelect = (next: PCountryKey) => {
    setCountry(next);
    setMaskCountry(next); // update formatter immediately
  };

  const label = useMemo(() => (isComplete ? 'complete' : 'incomplete'), [isComplete]);

  return (
    <div>
      <select value={country} onChange={(e) => onCountrySelect(e.target.value as PCountryKey)}>
        <option value="US">US</option>
        <option value="GB">GB</option>
        <option value="DE">DE</option>
      </select>
      <input ref={ref} type="tel" />
      <p>{fullFormatted}</p>
      <p>{label}</p>
    </div>
  );
}

多租户:租户Id 默认国家+特定租户审定规则

import { useMemo, useState } from 'react';
import { usePhoneMask, type PCountryKey } from '@desource/phone-mask-react';

type TenantPolicy = {
  defaultCountry: PCountryKey;
  prefixRule?: RegExp;
};

const TENANT_POLICIES: Record<string, TenantPolicy> = {
  acme: { defaultCountry: 'US', prefixRule: /^(202|303)\d{7}$/ },
  globex: { defaultCountry: 'GB', prefixRule: /^7\d{9}$/ }
};

export function TenantPhoneInput({ tenantId }: { tenantId: string }) {
  const policy = TENANT_POLICIES[tenantId] ?? { defaultCountry: 'US' as const };
  const [digits, setDigits] = useState('');

  const phoneMask = usePhoneMask({
    value: digits,
    onChange: setDigits,
    country: policy.defaultCountry
  });

  const isTenantValid = useMemo(() => {
    if (!phoneMask.isComplete) return false;
    return policy.prefixRule ? policy.prefixRule.test(phoneMask.digits) : true;
  }, [phoneMask.isComplete, phoneMask.digits, policy.prefixRule]);

  return (
    <div>
      <input ref={phoneMask.ref} type="tel" />
      <p>Default country: {policy.defaultCountry}</p>
      <p>Tenant validation: {isTenantValid ? 'pass' : 'fail'}</p>
    </div>
  );
}

++ 显示格式

打电话 formatPhone(value, country?, options?) 直接载于JSX。 它返回文本, 不需要 CSS .

import { formatPhone } from '@desource/phone-mask-react/core';

function Contact({ phone }: { phone: string }) {
  return <span>{formatPhone(phone, 'US', { code: false, flag: true })}</span>;
}
// '+12345678888' displays as '🇺🇸 234 567 8888'.

奥米 country 以检测一个完整的国际编号 +; 传递给没有调用代码的号码, 或解析美国/CA等共享调用代码. 可选 PhoneFormatOptions 参数接受 code (默认) true和 flag (默认) false) (中文(简体) ).

该功能在SSF期间有效. 不支持的值保持不变; 空白, 仅空白, null,以及 undefined 值返回空文本。 见 格式规则 用于检测限度和实例.

* 构件 API

道具

说明: 该组件需要受控行为. 两者 value 财务报告和审定财务报表 onChange 需要道具.

interface PhoneInputProps {
  // Controlled value (digits only, without country code) - REQUIRED
  value: string;

  // Optional id/name applied to the underlying <input> for forms/autofill
  id?: string;
  name?: string;

  // Preselected country (ISO 3166-1 alpha-2)
  country?: CountryKey;

  // Auto-detect country from IP/locale
  detect?: boolean; // Default: true

  // Locale for country names
  locale?: string; // Default: browser language

  // Size variant
  size?: 'compact' | 'normal' | 'large'; // Default: 'normal'

  // Visual theme ("auto" | "light" | "dark")
  theme?: 'auto' | 'light' | 'dark'; // Default: 'auto'

  // Disabled state
  disabled?: boolean; // Default: false

  // Readonly state
  readonly?: boolean; // Default: false

  // Show copy button
  showCopy?: boolean; // Default: true

  // Show clear button
  showClear?: boolean; // Default: false

  // Show validation state (borders & outline)
  withValidity?: boolean; // Default: true

  // Custom search placeholder
  searchPlaceholder?: string; // Default: 'Search country or code...'

  // Custom no results text
  noResultsText?: string; // Default: 'No countries found'

  // Custom clear button label
  clearButtonLabel?: string; // Default: 'Clear phone number'

  // Dropdown menu custom CSS class
  dropdownClass?: string;

  // Disable default styles
  disableDefaultStyles?: boolean; // Default: false

  // Callback when the digits value changes - REQUIRED
  // Returns only the digits without country code (e.g. '234567890')
  onChange: (digits: string) => void;

  // Callback when the phone number changes.
  // Provides an object with:
  // - full: Full phone number with country code (e.g. +1234567890)
  // - fullFormatted: Full phone number formatted according to country rules (e.g. +1 234-567-890)
  // - digits: Only the digits of the phone number without country code (e.g. 234567890)
  onPhoneChange?: (value: PMaskPhoneNumber) => void;

  // Callback when the selected country changes
  onCountryChange?: (country: MaskFull) => void;

  // Callback when the validation state changes
  onValidationChange?: (isValid: boolean) => void;

  // Callback when the input is focused
  onFocus?: (event: FocusEvent<HTMLInputElement>) => void;

  // Callback when the input is blurred
  onBlur?: (event: FocusEvent<HTMLInputElement>) => void;

  // Callback when phone number is copied
  onCopy?: (value: string) => void;

  // Callback when input is cleared
  onClear?: () => void;

  // Render custom action buttons before default ones
  renderActionsBefore?: () => ReactNode;

  // Render custom flag icons in the country list and country selector
  renderFlag?: (country: MaskFull) => ReactNode;

  // Render custom copy button SVG
  renderCopySvg?: (copied: boolean) => ReactNode;

  // Render custom clear button SVG
  renderClearSvg?: () => ReactNode;
}

查找方法

const phoneInputRef = useRef<PhoneInputRef>(null);

phoneInputRef.current?.focus(); // Focuses the input
phoneInputRef.current?.blur(); // Blurs the input
phoneInputRef.current?.clear(); // Clears the input value
phoneInputRef.current?.selectCountry('GB'); // Programmatically selects a country by ISO code (e.g., 'US', 'DE', 'GB')
phoneInputRef.current?.getFullNumber(); // Returns the full phone number with country code (e.g., +1234567890)
phoneInputRef.current?.getFullFormattedNumber(); // Returns the full phone number formatted according to country rules (e.g., +1 234-567-890)
phoneInputRef.current?.getDigits(); // Returns only the digits of the phone number without country code (e.g., 234567890)
phoneInputRef.current?.isValid(); // Checks if the current phone number is valid
phoneInputRef.current?.isComplete(); // Checks if the current phone number is complete

胡克 API

选项

说明: 钩子需要受控的行为. 两者 value 财务报告和审定财务报表 onChange 需要选项.

interface UsePhoneMaskOptions {
  // Controlled value (digits only, without country code) - REQUIRED
  value: string;

  // Callback when the digits value changes - REQUIRED
  onChange: (digits: string) => void;

  // Predefined country ISO code (e.g., 'US', 'DE', 'GB')
  country?: string;

  // Locale for country names (default: navigator.language)
  locale?: string;

  // Auto-detect country from IP/locale (default: false)
  detect?: boolean;

  // Callback when the phone changes (full, fullFormatted, digits)
  onPhoneChange?: (phone: PMaskPhoneNumber) => void;

  // Country change callback
  onCountryChange?: (country: MaskFull) => void;
}

返回值

interface UsePhoneMaskReturn {
  // Ref to attach to your input element
  ref: RefObject<HTMLInputElement | null>;

  // Raw digits without formatting (e.g., "1234567890")
  digits: string;

  // Phone formatter instance
  formatter: FormatterHelpers;

  // Full phone number with country code (e.g., "+11234567890")
  full: string;

  // Full phone number formatted (e.g., "+1 123-456-7890")
  fullFormatted: string;

  // Whether the phone number is complete
  isComplete: boolean;

  // Whether the input is empty
  isEmpty: boolean;

  // Whether to show validation warning
  shouldShowWarn: boolean;

  // Current country data
  country: MaskFull;

  // Change country programmatically
  setCountry: (countryCode: string) => void;

  // Clear the input
  clear: () => void;
}

组件样式

CSS 自定义属性

通过 CSS 变量自定义颜色 :

.desource-phone-input,
.desource-phone-dropdown {
  /* Colors */
  --pi-bg: #ffffff;
  --pi-fg: #111827;
  --pi-muted: #6b7280;
  --pi-border: #e5e7eb;
  --pi-border-hover: #d1d5db;
  --pi-border-focus: #3b82f6;
  --pi-focus-ring: 3px solid rgb(59 130 246 / 0.15);
  --pi-disabled-bg: #f9fafb;
  --pi-disabled-fg: #9ca3af;
  /* Sizes */
  --pi-font-size: 16px;
  --pi-height: 44px;
  /* Spacing */
  --pi-padding: 12px;
  /* Border radius */
  --pi-radius: 8px;
  /* Shadows */
  --pi-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
  --pi-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -2px rgb(0 0 0 / 0.05);
  /* Validation */
  --pi-warning: #f59e0b;
  --pi-warning-light: #fbbf24;
  --pi-success: #10b981;
  --pi-focus-ring-warning: 3px solid rgb(245 158 11 / 0.15);
  --pi-focus-ring-success: 3px solid rgb(16 185 129 / 0.15);
}

黑暗主题

<PhoneInput value={phone} onChange={setPhone} theme="dark" />

或与CSS: (中文(简体) )

.desource-phone-input.theme-dark {
  --pi-bg: #1f2937;
  --pi-fg: #f9fafb;
  --pi-border: #374151;
}

实例

有验证

import { useState } from 'react';
import { PhoneInput } from '@desource/phone-mask-react';

function Example() {
  const [phone, setPhone] = useState('');
  const [isValid, setIsValid] = useState(false);

  return (
    <div>
      <PhoneInput value={phone} onChange={setPhone} onValidationChange={setIsValid} />

      {isValid && <span>✓ Valid phone number</span>}
    </div>
  );
}

自动检测国家

import { useState } from 'react';
import { PhoneInput } from '@desource/phone-mask-react';

function Example() {
  const [phone, setPhone] = useState('');
  const [detectedCountry, setDetectedCountry] = useState('');

  return (
    <>
      <PhoneInput
        value={phone}
        detect
        onChange={setPhone}
        onCountryChange={(country) => setDetectedCountry(country.name)}
      />

      {detectedCountry && <p>Detected: {detectedCountry}</p>}
    </>
  );
}

带有窗体库

反应钩形

import { useForm, Controller } from 'react-hook-form';
import { PhoneInput } from '@desource/phone-mask-react';

function Example() {
  const { control } = useForm({
    defaultValues: { phone: '' }
  });

  return (
    <Controller
      name="phone"
      control={control}
      render={({ field }) => (
        <PhoneInput value={field.value} onChange={(digits) => field.onChange(digits)} onBlur={field.onBlur} />
      )}
    />
  );
}

多个输入

import { useState } from 'react';
import { PhoneInput } from '@desource/phone-mask-react';

function Example() {
  const [form, setForm] = useState({ mobile: '', home: '', work: '' });

  return (
    <div className="form">
      <label>
        Mobile
        <PhoneInput value={form.mobile} onChange={(digits) => setForm({ ...form, mobile: digits })} />
      </label>

      <label>
        Home
        <PhoneInput value={form.home} onChange={(digits) => setForm({ ...form, home: digits })} />
      </label>

      <label>
        Work
        <PhoneInput value={form.work} onChange={(digits) => setForm({ ...form, work: digits })} />
      </label>
    </div>
  );
}

QQ 浏览器支持

  • 克罗梅/第90号+
  • Firefox 88+ (英语)
  • 萨法里14+
  • iOS 萨法里14+
  • Chrome 移动

包含什么

@desource/phone-mask-react/
├── dist/
│   ├── index.mjs               # Main ESM entry
│   ├── index.cjs               # Main CommonJS entry
│   ├── core.mjs                # Core kit utilities and mask data subpath
│   ├── core.cjs                # Core kit utilities and mask data CJS subpath
│   ├── phone-mask-react.css    # Component styles
│   └── *.d.ts, *.d.cts         # ESM and CommonJS declarations
├── README.md                   # This file
└── package.json                # Package manifest

许可证

麻省理工学院 2026 来源实验室

捐款

见 贡献指南 用于开发、测试和出版检查.


由 Q 制作 来源实验室

版本与发布记录

@desource/phone-mask-react 共发布 19 个版本,首次发布于 2026/02/16;过去 12 个月发布了 19 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2.1.0latest2026/11/074 天前
2.0.02026/10/3111 天前
1.7.02026/10/101 个月前
1.6.42026/09/261 个月前
1.6.32026/09/082 个月前
1.6.22026/08/242 个月前

关于 @desource/phone-mask-react 的常见问题

@desource/phone-mask-react 是什么?

QQ 反应组件和钩子用于国际电话号码输入,并带有智能口罩. 由@desource/phone-mask和Google libphone数字提供.

如何安装 @desource/phone-mask-react?

在项目目录运行 npm install @desource/phone-mask-react,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^18.0.0 || ^19.0.0)、react-dom(^18.0.0 || ^19.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@desource/phone-mask-react 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@desource/phone-mask-react 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@desource/phone-mask-react 可以商用吗?

@desource/phone-mask-react 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@desource/phone-mask-react 的下载量有多少?

根据 npm 官方下载统计,@desource/phone-mask-react 在 2026/10/12 – 2026/11/10 这 30 天内被下载 19,627 次,日均约 654 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@desource/phone-mask-react 还在维护吗?

最新版本 2.1.0 发布于 2026/11/07(4 天前);至今共发布 19 个版本,其中过去 12 个月发布了 19 个;首次发布于 2026/02/16。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。