LogoSkills

coui-phone-input

Activate when creating phone number inputs, country code selectors, international phone fields, or dial code inputs using PhoneInput with PhoneNumber, Country, CoreCountry, PhoneInputValue, CorePho...

CoUI PhoneInput#

ํ•œ๋งˆ๋””๋กœ (๋น„๊ฐœ๋ฐœ์ž์šฉ)#

์ด ์Šคํ‚ฌ์€ ํ™”๋ฉด์— "์ „ํ™”๋ฒˆํ˜ธ ์ž…๋ ฅ์นธ"์„ ๋งŒ๋“ค ๋•Œ ์“ฐ๋Š” ์‚ฌ์šฉ๋ฒ• ์„ค๋ช…์„œ์ž…๋‹ˆ๋‹ค. ๊ตญ๊ฐ€ ๊นƒ๋ฐœ๊ณผ ๊ตญ๊ฐ€๋ฒˆํ˜ธ(์˜ˆ: ํ•œ๊ตญ +82)๋ฅผ ๊ณ ๋ฅด๋Š” ๋ฒ„ํŠผ๊ณผ ๋ฒˆํ˜ธ ์ž…๋ ฅ์นธ์ด ํ•œ ์นธ ์•ˆ์— ํ•ฉ์ณ์ง„ ํ˜•ํƒœ์˜ˆ์š”. ๋งˆ์น˜ ํ•ด์™ธ ๋ฐฐ์†ก ์ฃผ๋ฌธ์„œ์—์„œ ๋‚˜๋ผ๋ฅผ ๋จผ์ € ๊ณ ๋ฅด๋ฉด ์•ž์ž๋ฆฌ ๋ฒˆํ˜ธ๊ฐ€ ์ž๋™์œผ๋กœ ์ฑ„์›Œ์ง€๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๋‚˜ AI๊ฐ€ ์ด ์ž…๋ ฅ์นธ์„ ์ผ๊ด€๋œ ๋ชจ์–‘์œผ๋กœ ๋น ๋ฅด๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ค๋‹ˆ๋‹ค.

๋ฌด์—‡์„ยท์–ธ์ œ (๋น„๊ฐœ๋ฐœ์ž์šฉ)#

  • ๋ฌด์—‡์„ ํ•ด์ฃผ๋‚˜์š”: ๊ตญ๊ฐ€ ์„ ํƒ ๋ฒ„ํŠผ๊ณผ ์ „ํ™”๋ฒˆํ˜ธ ์ž…๋ ฅ์นธ์„ ํ•˜๋‚˜๋กœ ๋ฌถ์€ ์ปดํฌ๋„ŒํŠธ(PhoneInput)๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๋ ค์ค๋‹ˆ๋‹ค. ๋‚˜๋ผ๋ฅผ ๊ณ ๋ฅด๋ฉด ๊ตญ๊ฐ€๋ฒˆํ˜ธ ์•ž์ž๋ฆฌ๊ฐ€ ์ž๋™์œผ๋กœ ๋ฐ”๋€Œ๊ณ , ๊ธฐ๋ณธ์ ์œผ๋กœ ์ˆซ์ž๋งŒ ์ž…๋ ฅ๋˜๋„๋ก ๋ง‰์•„์ค๋‹ˆ๋‹ค. ๊ตญ๊ฐ€ ์„ ํƒ์ฐฝ ์•ˆ์—๋Š” ๊ฒ€์ƒ‰์นธ์ด ์žˆ์–ด ๋‚˜๋ผ ์ด๋ฆ„ยท๊ตญ๊ฐ€๋ฒˆํ˜ธยท๊ตญ๊ฐ€์ฝ”๋“œ๋กœ ๋ฐ”๋กœ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์–ธ์ œ ์ž‘๋™ํ•˜๋‚˜์š”: ํšŒ์›๊ฐ€์ž…, ๋ณธ์ธ ์ธ์ฆ, ์—ฐ๋ฝ์ฒ˜ ์ž…๋ ฅ์ฒ˜๋Ÿผ "์ „ํ™”๋ฒˆํ˜ธ๋ฅผ ๋ฐ›๋Š” ํ™”๋ฉด"์„ ๋งŒ๋“ค ๋•Œ ์ด ์Šคํ‚ฌ์ด ์ฐธ๊ณ ๋ฉ๋‹ˆ๋‹ค.
  • ์–ด๋””์—์„œ ์“ฐ๋‚˜์š”: ๋ชจ๋ฐ”์ผ ์•ฑ(Flutter)๊ณผ ์›น์‚ฌ์ดํŠธ(Web) ๋‘ ๊ณณ ๋ชจ๋‘์—์„œ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ฌด์—‡์„ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ๋‚˜์š”: ๋ณด์—ฌ์ค„ ๋‚˜๋ผ ๋ชฉ๋ก ์ œํ•œ, ์•ˆ๋‚ด ๋ฌธ๊ตฌ(placeholder), ์ž…๋ ฅ์นธ ๋ชจ์–‘(๋‘ฅ๊ทผ ์ •๋„ยท๋†’์ดยท๊ฐ„๊ฒฉยท์ƒ‰์ƒ ๋“ฑ), ๋น„ํ™œ์„ฑํ™” ์ƒํƒœ ๋“ฑ์„ ์ž์œ ๋กญ๊ฒŒ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ์šฉ์–ด (๋น„๊ฐœ๋ฐœ์ž์šฉ)#

์šฉ์–ด์‰ฌ์šด ์„ค๋ช…
dial code (๊ตญ๊ฐ€๋ฒˆํ˜ธ)๋‚˜๋ผ๋งˆ๋‹ค ์ •ํ•ด์ง„ ์ „ํ™” ์•ž์ž๋ฆฌ ๋ฒˆํ˜ธ. ์˜ˆ: ํ•œ๊ตญ +82, ๋ฏธ๊ตญ +1
country / CoreCountry์„ ํƒํ•œ ๋‚˜๋ผ ์ •๋ณด(๊ตญ๊ฐ€์ฝ”๋“œยท๊ตญ๊ฐ€๋ฒˆํ˜ธยท์ด๋ฆ„)๋ฅผ ๋‹ด๋Š” ๋‹จ์œ„
placeholder์ž…๋ ฅ์นธ์ด ๋น„์–ด ์žˆ์„ ๋•Œ ํ๋ฆฌ๊ฒŒ ๋ณด์ด๋Š” ์•ˆ๋‚ด ๋ฌธ๊ตฌ. ์˜ˆ: "์ „ํ™”๋ฒˆํ˜ธ"
onChanged๋‚˜๋ผ๋‚˜ ๋ฒˆํ˜ธ๊ฐ€ ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ์•Œ๋ ค์ฃผ๋Š” ์‹ ํ˜ธ(์—ฐ๊ฒฐ ๋™์ž‘)
fullNumber๊ตญ๊ฐ€๋ฒˆํ˜ธ์™€ ๋ฒˆํ˜ธ๋ฅผ ํ•ฉ์นœ ์ „์ฒด ๋ฒˆํ˜ธ. ์˜ˆ: +821012345678
enabled / disabled์ž…๋ ฅ์นธ์„ ์ผœ๊ณ (์‚ฌ์šฉ ๊ฐ€๋Šฅ) ๋„๋Š”(ํ๋ฆฌ๊ฒŒ ๋น„ํ™œ์„ฑํ™”) ์ƒํƒœ
style / theme์ž…๋ ฅ์นธ์˜ ๋ชจ์–‘ยท์ƒ‰ยทํฌ๊ธฐ ๊ฐ™์€ ๋””์ž์ธ ์„ค์ •
Flutter / Web(Jaspr)๊ฐ๊ฐ ๋ชจ๋ฐ”์ผ ์•ฑ๊ณผ ์›น์‚ฌ์ดํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ๊ธฐ์ˆ 

Overview#

PhoneInput is a form component that combines a country selector trigger and a phone number text field inside a single bordered container. Tapping the selector opens a country picker (search input + country list) that both platforms share as the same UX: search matches country name, dial code, or ISO code (case-insensitive). Selecting a country updates the dial code prefix; the number field accepts only digits by default. The Flutter and Web implementations share the same CorePhoneInputContract interface and CorePhoneInputStyle design tokens.

Resolve priority: widget.phoneInputStyle > CorePhoneInputTheme.style (project theme) > design system defaults.

Variants & sizes#

PhoneInput has no variant or size enum (no CoreComponentSize axis). It is a single-form component; every visual knob flows through the single style slot phoneInputStyle: CorePhoneInputStyle (full field set below).

AxisValues
variantโ€” (none)
size โ€” (none; use CorePhoneInputStyle.height, default CoreSpace.space40)
style slotphoneInputStyle: CorePhoneInputStyle

Flutter (coui_flutter)#

Import#

import 'package:coui_flutter/coui_flutter.dart';

The Country enum (and Countries helper) is re-exported from the phonecodes package through the same barrel โ€” no extra import needed.

Basic usage#

PhoneInput(
  initialCountry: Country.unitedStates,
  onChanged: (phoneNumber) {
    // phoneNumber.fullNumber  โ†’ '+11234567890'
    // phoneNumber.number      โ†’ '1234567890'  (without dial code)
    // phoneNumber.value       โ†’ null when empty, fullNumber otherwise
    print(phoneNumber.fullNumber);
  },
)

With initial value#

PhoneInput(
  initialValue: PhoneNumber(Country.southKorea, '1012345678'),
  onChanged: (phoneNumber) => print(phoneNumber.fullNumber),
)

PhoneNumber uses positional parameters: PhoneNumber(country, number). When initialValue is provided, its country takes precedence over initialCountry and its number over initialNumber.

With placeholder and restricted country list#

PhoneInput(
  initialCountry: Country.southKorea,
  placeholder: 'Phone number',
  countries: const [Country.southKorea, Country.unitedStates, Country.japan],
  onChanged: (phoneNumber) => print(phoneNumber.fullNumber),
)

With external controller#

final _controller = TextEditingController();

PhoneInput(
  controller: _controller,
  initialCountry: Country.unitedStates,
  onChanged: (phoneNumber) => print(phoneNumber.fullNumber),
)

An internal controller is created (and disposed) automatically when controller is null.

Disabled state#

PhoneInput(
  initialCountry: Country.unitedStates,
  enabled: false,
)

Disabled rendering wraps the component in IgnorePointer + Opacity (default opacity 0.5), matching Web's container-level opacity.

Style override via phoneInputStyle#

PhoneInput(
  initialCountry: Country.unitedStates,
  phoneInputStyle: const CorePhoneInputStyle(
    borderRadius: CoreBorderRadius.all(CoreRadius.radius8),
    height: CoreSpace.space48,
    selectorPadding: CoreEdgeInsets.symmetric(horizontal: CoreSpace.space16),
    inputFieldPadding: CoreEdgeInsets.symmetric(horizontal: CoreSpace.space16),
    flagSize: 20.0,
    dropdownFlagSize: 20.0,
    hoverColor: CoreColor.token(CoreColors.tertiary),
  ),
  onChanged: (phoneNumber) => print(phoneNumber.fullNumber),
)

Project-level theme (CorePhoneInputTheme)#

// Inside your CoUI theme setup:
CoreComponentTheme(
  phoneInput: CorePhoneInputTheme(
    style: CorePhoneInputStyle(
      borderRadius: CoreBorderRadius.all(CoreRadius.radius4),
      height: CoreSpace.space40,
    ),
  ),
)

Parameters โ€” PhoneInput (Flutter)#

ParameterTypeDefaultDescription
initialCountry Country? null (falls back to Country.unitedStates) Country shown when no initialValue is provided
initialNumber String? null Phone number text (without dial code) used as initial field content
initialValue PhoneNumber? null Combined initial value; country overrides initialCountry , number overrides initialNumber
onChanged ValueChanged<PhoneNumber>? null Called on every country or number change
controller TextEditingController? null External text controller; an internal one is created when null
placeholder String? null Hint text rendered inside the number field when empty
countries List<Country>? null (โ†’ Country.values) Allowed countries shown in the picker; null means all
enabled bool true Disables interaction and applies disabled opacity when false
onlyNumber bool true keyboardType: phone + FilteringTextInputFormatter.digitsOnly
filterPlusCode bool true Strips leading dial code (e.g. +1) or bare + from typed input
filterZeroCode bool true Strips a leading 0 from typed input
filterCountryCode bool true Strips the numeric country-code prefix (without +) from typed input
phoneInputStyle CorePhoneInputStyle? null Per-instance style override

The three filter* checks run as an if/else-if chain in this order โ€” filterPlusCode (dial code with +, then bare +) โ†’ filterZeroCode โ†’ filterCountryCode โ€” so at most one filter applies per value read.

Behavior notes (Flutter)#

  • Country picker popup: opens anchored below the selector trigger (popover, no vertical invert) with a Search country field on top and the country list below. Search matches name, dialCode, or code (case-insensitive). An empty result shows a muted No results hint.
  • Form integration: the state mixes in FormValueSupplier<PhoneNumber, PhoneInput>, so PhoneInput participates in the CoUI form value system automatically; a replaced form value is written back into the text controller.
  • Autofill: the number field sets autofillHints: [AutofillHints.telephoneNumber].

PhoneNumber (value object, Flutter)#

MemberTypeDescription
countryCountrySelected country enum value
numberStringPhone number without dial code
fullNumber String dialCode + number (e.g. +821012345678)
value String? null when number is empty, fullNumber otherwise
toString() String '' when empty, fullNumber otherwise

Country enum (from phonecodes, re-exported)#

Use Country.<camelCaseName> enum values โ€” e.g. Country.unitedStates, Country.southKorea, Country.japan, Country.unitedKingdom. Use Country.values for the full list. Each value exposes name, code, dialCode, and flag (emoji string).

Note: Korea is Country.southKorea โ€” there is no Country.korea member.


Web / Jaspr (coui_web)#

Import#

import 'package:coui_web/coui_web.dart';

Basic usage#

PhoneInput(
  initialCountry: const CoreCountry(code: 'US', dialCode: '+1', name: 'United States'),
  placeholder: 'Phone number',
  onChanged: (value) {
    // value.fullNumber  โ†’ '+11234567890'
    // value.number      โ†’ '1234567890'
    // value.countryCode โ†’ 'US'
    // value.dialCode    โ†’ '+1'
    print(value.fullNumber);
  },
)

With predefined default countries#

PhoneInput.defaultCountries contains 10 common countries (US, KR, JP, GB, DE, FR, CN, IN, CA, AU). When countries is null, this list is used.

PhoneInput(
  initialCountry: const CoreCountry(code: 'KR', dialCode: '+82', name: 'South Korea'),
  countries: PhoneInput.defaultCountries,
  onChanged: (value) => print(value.fullNumber),
)

With custom country list#

PhoneInput(
  initialCountry: const CoreCountry(code: 'KR', dialCode: '+82', name: 'South Korea'),
  countries: const [
    CoreCountry(code: 'KR', dialCode: '+82', name: 'South Korea'),
    CoreCountry(code: 'US', dialCode: '+1', name: 'United States'),
    CoreCountry(code: 'JP', dialCode: '+81', name: 'Japan'),
  ],
  onChanged: (value) => print(value.fullNumber),
)

With HTML attributes and CSS#

PhoneInput(
  id: 'signup-phone',
  classes: 'my-phone-input',
  initialCountry: const CoreCountry(code: 'US', dialCode: '+1', name: 'United States'),
  attributes: const {'data-testid': 'phone-input'},
  onChanged: (value) => print(value.fullNumber),
)

A caller-supplied id becomes the root element id and the outside-click scope for closing the dropdown; when omitted, a generated co-phone-input-N id is used.

Style override via phoneInputStyle#

PhoneInput(
  initialCountry: const CoreCountry(code: 'US', dialCode: '+1', name: 'United States'),
  phoneInputStyle: const CorePhoneInputStyle(
    borderRadius: CoreBorderRadius.all(CoreRadius.radius8),
    height: CoreSpace.space48,
    popupMaxWidth: CoreSpace.space248,
    popupMaxHeight: CoreSpace.space248,
  ),
  onChanged: (value) => print(value.fullNumber),
)

Parameters โ€” PhoneInput (Web)#

ParameterTypeDefaultDescription
initialCountry CoreCountry? null (falls back to CoreCountry(code: 'US', dialCode: '+1', name: 'United States') ) Country shown initially
initialNumber String? null Phone number text (without dial code) used as initial field value
onChanged CoreValueChanged<PhoneInputValue>? null Called on every country or number change
onlyNumber bool true Sets inputmode="numeric" (otherwise inputmode="tel") on the number field
placeholder String? null HTML placeholder attribute on the number field
countries List<CoreCountry>? null (โ†’ PhoneInput.defaultCountries) Countries available in the picker
enabled bool true Adds disabled attribute and applies disabled opacity on the root when false
phoneInputStyle CorePhoneInputStyle? null Per-instance style override
id String? null HTML id for the root <div> (also the outside-click scope)
classes String? null Additional CSS classes for the root element
css Styles? null Inline CSS styles merged onto the root element
attributes Map<String, String>? null Extra HTML attributes for the root element
eventHandlers Map<String, List<UiEventHandler>> {} Custom DOM event handlers for the root element
onClick / onMouseEnter / onMouseLeave UiMouseEventHandler? null Root-level mouse event passthrough
onKeyDown / onKeyUp UiKeyboardEventHandler? null Root-level keyboard event passthrough
onInput / onChange UiInputEventHandler? null Root-level input event passthrough

Web does not use TextEditingController โ€” the contract's controller field is typed Null and always returns null.

Behavior notes (Web)#

  • The number field renders as <input type="tel" autocomplete="tel">.
  • The dropdown (role="listbox") renders only while open, with a Search country input on top; clicking outside the component closes it. Each country row is a <button role="option">.
  • Accessibility: the selector trigger carries aria-label="Select country", aria-haspopup="listbox", and aria-expanded; the search field carries aria-label="Search country".
  • When the parent swaps initialCountry to a new non-null value, the selected country follows (didUpdateComponent).
  • PhoneInput.flagEmoji(code) (delegating to CoreCountry.flagEmoji) converts an ISO 2-letter code to its flag emoji.

PhoneInputValue (value object, Web)#

MemberTypeDescription
countryCode String ISO 2-letter code (e.g. 'KR')
dialCode String Dial code with prefix (e.g. '+82')
number String Phone number without dial code (default '')
fullNumberStringdialCode + number
value String? null when number is empty, fullNumber otherwise

Constructor uses named parameters: PhoneInputValue(countryCode: 'KR', dialCode: '+82', number: '1012345678').

CoreCountry (value object, from coui_core)#

const CoreCountry(code: 'KR', dialCode: '+82', name: 'South Korea')
FieldTypeDescription
codeStringISO 2-letter country code
dialCode String Dial code with + prefix
nameStringLocalized country name

Use CoreCountry.flagEmoji(code) to convert a code string to its flag emoji (returns '' when code is not exactly 2 characters).


CorePhoneInputStyle fields (single style slot)#

All fields are optional overrides merged over the chain defaults โ†’ CorePhoneInputTheme.style โ†’ phoneInputStyle. Defaults are static fields on CorePhoneInputStyle (static const, except defaultDialCodeTextStyle which is static final) โ€” the single source of truth shared by both platforms.

FieldTypeDefault
borderRadius CoreBorderRadius? CoreBorderRadius.all(CoreRadius.radius4)
flagGapStyle CoreGapStyle? CoreGapStyle(size: CoreSpace.space8, crossAxisExtent: 0)
countryGapStyle CoreGapStyle? CoreGapStyle(size: CoreSpace.space16, crossAxisExtent: 0)
maxWidthdouble?200.0
padding CoreEdgeInsets? null (flush row layout)
heightdouble?CoreSpace.space40
borderWidth double? CoreStrokeWidth.stroke1
inputFieldPadding CoreEdgeInsets? CoreEdgeInsets.symmetric(horizontal: CoreSpace.space12)
selectorPadding CoreEdgeInsets? CoreEdgeInsets.symmetric(horizontal: CoreSpace.space12)
dropdownItemPadding CoreEdgeInsets? CoreEdgeInsets.symmetric(horizontal: CoreSpace.space12, vertical: CoreSpace.space8)
dropdownItemGapStyle CoreGapStyle? CoreGapStyle(size: CoreSpace.space8, crossAxisExtent: 0)
popupMaxWidth double? CoreSpace.space248
popupMaxHeight double? CoreSpace.space248
popoverTopOffset double? CoreSpace.space4
chevronIconStyle CoreIconStyle? CoreIconStyle(size: 12.0)
flagSizedouble?16.0
dropdownFlagSizedouble?16.0
disabledOpacitydouble?0.5
popupBorderRadius CoreBorderRadius? CoreBorderRadius.all(CoreRadius.radius8)
dropdownDialCodeTextStyle CoreTextStyle? CoreTextStyle.token(CoreTextStyles.bodySmall, color: CoreColor.token(CoreColors.onSurfaceVariant))
backgroundColor CoreColor? CoreColor.token(CoreColors.surface)
borderColor CoreColor? CoreColor.token(CoreColors.outlineVariant)
hoverColor CoreColor? CoreColor.token(CoreColors.tertiary)
separatorColor CoreColor? CoreColor.token(CoreColors.outlineVariant)
placeholderColor CoreColor? CoreColor.token(CoreColors.onSurfaceVariant)
chevronColor CoreColor? CoreColor.token(CoreColors.onSurface)
disabledChevronColor CoreColor? CoreColor.token(CoreColors.onSurfaceVariant)
dialCodeTextStyle CoreTextStyle? labelLarge role + medium weight + onSurface color
disabledDialCodeColor CoreColor? CoreColor.token(CoreColors.onSurfaceVariant)
flagTextStyle CoreTextStyle? CoreTextStyle.token(CoreTextStyles.labelLarge)
bodyTextStyle CoreTextStyle? CoreTextStyle.token(CoreTextStyles.bodySmall)

CorePhoneInputStyle also provides merge(other) and copyWith(...).


Flutter โ†” Web differences#

ConceptFlutterWeb (Jaspr)
Widget class PhoneInput (extends StatefulWidget) PhoneInput (extends UiStatefulComponent)
Contract CorePhoneInputContract<TextEditingController?, PhoneNumber, Country> CorePhoneInputContract<Null, PhoneInputValue, CoreCountry>
Country type Country (enum, from phonecodes) CoreCountry (value object, from coui_core)
Value type in onChanged PhoneNumber (positional ctor) PhoneInputValue (named ctor)
Callback type ValueChanged<PhoneNumber>? CoreValueChanged<PhoneInputValue>?
Controller TextEditingController? Null (always null, not supported)
Default country fallback Country.unitedStates CoreCountry(code: 'US', dialCode: '+1', name: 'United States')
Country list default Country.values (all countries) PhoneInput.defaultCountries (10 common countries)
Input filters filterPlusCode / filterZeroCode / filterCountryCode params โ€” (no filter params)
initialValue (combined) supported (PhoneNumber?) โ€” (use initialCountry + initialNumber)
onlyNumber effect phone keyboard + digits-only formatter inputmode="numeric" vs "tel"
Disabled rendering IgnorePointer + Opacity(disabledOpacity) disabled attribute + opacity inline CSS on root
Picker presentation popover overlay below the trigger absolutely-positioned <div role="listbox"> sibling
HTML extras โ€” id , classes , css , attributes , eventHandlers , onClick , onInput , onChange , onKeyDown , onKeyUp , onMouseEnter , onMouseLeave
Flag rendering country.flag emoji string PhoneInput.flagEmoji(code) / CoreCountry.flagEmoji(code)
Form integration FormValueSupplier<PhoneNumber, PhoneInput> โ€”

Shared across both platforms: CorePhoneInputStyle, CorePhoneInputTheme, CorePhoneInputContract, search-driven country picker UX, and the resolve chain defaults โ†’ theme.style โ†’ phoneInputStyle.


v0.127 Migration (Legacy)#

v0.127 removed the Co prefix from widget classes (hard break โ€” no aliases). Core* style/theme/contract names and the value objects are unchanged.

Legacy (โŒ removed)v0.127 Canonical
โŒ CoPhoneInputPhoneInput
โŒ CoPhoneInput.defaultCountries PhoneInput.defaultCountries
โŒ CoPhoneInput.flagEmojiPhoneInput.flagEmoji
โŒ CoLucideIcons (internal chevron icon set)LucideIcons
โŒ per-component src/ imports single barrel: package:coui_flutter/coui_flutter.dart / package:coui_web/coui_web.dart

Unchanged names: CorePhoneInputStyle, CorePhoneInputTheme, CorePhoneInputContract, PhoneNumber, PhoneInputValue, CoreCountry, Country.