@desource/phone-mask-svelte 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @desource/phone-mask-svelte
2
2
 
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Svelte Upgrades:
8
+ - Added attachment `phoneMaskAttachment` for usage in native input (for Svelte 5.29+ versions)
9
+ - Added action `phoneMaskAction` for usage in native input (for Svelte 5.0+ versions)
10
+ - Improved keyboard country selection flow and active-descendant accessibility behavior
11
+ - Refined dropdown/key navigation handling and related focus behavior
12
+ - `usePhoneMask` now exposes `formatter` in the return object
13
+
14
+ - Vue Upgrades:
15
+ - Directive was refactored to align with Svelte action
16
+ - Improved keyboard country selection flow and active-descendant accessibility behavior
17
+ - Refined dropdown/key navigation handling and related focus behavior
18
+ - `usePhoneMask` now exposes `formatter` in the return object
19
+
20
+ - React Upgrades:
21
+ - Improved keyboard country selection flow and active-descendant accessibility behavior
22
+ - Refined dropdown/key navigation handling and related focus behavior
23
+ - `usePhoneMask` now exposes `formatter` in the return object
24
+
25
+ - Core Upgrades:
26
+ - Fixed edge cases in mask variant selection and improved input handler robustness
27
+ - Applied reliability-focused refactors in formatter/handlers and build script generation logic
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies []:
32
+ - @desource/phone-mask@1.1.0
33
+
3
34
  ## 1.0.0
4
35
 
5
36
  ### Major Changes
package/README.md CHANGED
@@ -19,7 +19,7 @@ Beautiful, accessible, extreme small & tree-shakeable Svelte 5 phone input with
19
19
  - ♿ **Accessible** — ARIA labels, keyboard navigation
20
20
  - 📱 **Mobile-friendly** — Optimized for touch devices
21
21
  - 🎯 **TypeScript** — Full type safety
22
- - 🧩 **Two modes** — Component or composable
22
+ - 🧩 **Four modes** — Component, composable, attachment, or action
23
23
  - ⚡ **Optimized** — Tree-shaking and code splitting
24
24
 
25
25
  ## 📦 Installation
@@ -49,6 +49,18 @@ Composable mode:
49
49
  import { usePhoneMask } from '@desource/phone-mask-svelte';
50
50
  ```
51
51
 
52
+ Attachment mode (for existing `<input>` elements, requires Svelte 5.29+):
53
+
54
+ ```ts
55
+ import { phoneMaskAttachment as phoneMask } from '@desource/phone-mask-svelte';
56
+ ```
57
+
58
+ Action mode (for existing `<input>` elements, works with all Svelte 5 versions):
59
+
60
+ ```ts
61
+ import { phoneMaskAction as phoneMask } from '@desource/phone-mask-svelte';
62
+ ```
63
+
52
64
  ### Component Mode
53
65
 
54
66
  ```svelte
@@ -94,6 +106,98 @@ For custom input implementations:
94
106
  </div>
95
107
  ```
96
108
 
109
+ ### Attachment Mode
110
+
111
+ For existing `<input>` elements without a wrapper component. Requires Svelte 5.29+.
112
+
113
+ ```svelte
114
+ <script lang="ts">
115
+ import { phoneMaskAttachment as phoneMask } from '@desource/phone-mask-svelte';
116
+ import type { PMaskPhoneNumber, PMaskFull } from '@desource/phone-mask-svelte';
117
+
118
+ let country = $state('US');
119
+
120
+ function handleChange(phone: PMaskPhoneNumber) {
121
+ console.log('Full:', phone.full, 'Digits:', phone.digits);
122
+ }
123
+
124
+ function handleCountryChange(c: PMaskFull) {
125
+ console.log('Country:', c.name);
126
+ }
127
+ </script>
128
+
129
+ <div class="phone-wrapper">
130
+ <select bind:value={country}>
131
+ <option value="US">🇺🇸 +1</option>
132
+ <option value="GB">🇬🇧 +44</option>
133
+ <option value="DE">🇩🇪 +49</option>
134
+ </select>
135
+
136
+ <input
137
+ {@attach phoneMask({ country, onChange: handleChange, onCountryChange: handleCountryChange })}
138
+ placeholder="Phone number"
139
+ />
140
+ </div>
141
+ ```
142
+
143
+ Shorthand (country code string):
144
+
145
+ ```svelte
146
+ <input {@attach phoneMask('US')} />
147
+ ```
148
+
149
+ With auto-detection:
150
+
151
+ ```svelte
152
+ <input {@attach phoneMask({ detect: true, onChange: handleChange })} />
153
+ ```
154
+
155
+ ### Action Mode
156
+
157
+ For existing `<input>` elements without a wrapper component. Works with **all Svelte 5 versions** (including pre-5.29). Reactive parameter changes are applied through Svelte's `use:` action `update()` lifecycle hook.
158
+
159
+ ```svelte
160
+ <script lang="ts">
161
+ import { phoneMaskAction as phoneMask } from '@desource/phone-mask-svelte';
162
+ import type { PMaskPhoneNumber, PMaskFull } from '@desource/phone-mask-svelte';
163
+
164
+ let country = $state('US');
165
+
166
+ function handleChange(phone: PMaskPhoneNumber) {
167
+ console.log('Full:', phone.full, 'Digits:', phone.digits);
168
+ }
169
+
170
+ function handleCountryChange(c: PMaskFull) {
171
+ console.log('Country:', c.name);
172
+ }
173
+ </script>
174
+
175
+ <div class="phone-wrapper">
176
+ <select bind:value={country}>
177
+ <option value="US">🇺🇸 +1</option>
178
+ <option value="GB">🇬🇧 +44</option>
179
+ <option value="DE">🇩🇪 +49</option>
180
+ </select>
181
+
182
+ <input
183
+ use:phoneMask={{ country, onChange: handleChange, onCountryChange: handleCountryChange }}
184
+ placeholder="Phone number"
185
+ />
186
+ </div>
187
+ ```
188
+
189
+ Shorthand (country code string):
190
+
191
+ ```svelte
192
+ <input use:phoneMask={'US'} />
193
+ ```
194
+
195
+ With auto-detection:
196
+
197
+ ```svelte
198
+ <input use:phoneMask={{ detect: true, onChange: handleChange }} />
199
+ ```
200
+
97
201
  ## 📖 Component API
98
202
 
99
203
  ### Props
@@ -276,15 +380,40 @@ interface UsePhoneMaskOptions {
276
380
 
277
381
  ```ts
278
382
  interface UsePhoneMaskReturn {
279
- inputRef: HTMLInputElement | null; // Bind to <input> with bind:this
383
+ // Ref to attach to your input element
384
+ inputRef: HTMLInputElement | null;
385
+
386
+ // Raw digits without formatting (e.g., "1234567890")
280
387
  digits: string;
388
+
389
+ // Phone formatter instance
390
+ formatter: FormatterHelpers;
391
+
392
+ // Full phone number with country code (e.g., "+11234567890")
281
393
  full: string;
394
+
395
+ // Full phone number formatted (e.g., "+1 123-456-7890")
282
396
  fullFormatted: string;
397
+
398
+ // Whether the phone number is complete
283
399
  isComplete: boolean;
400
+
401
+ // Whether the input is empty
284
402
  isEmpty: boolean;
403
+
404
+ // Whether to show validation warning
285
405
  shouldShowWarn: boolean;
406
+
407
+ // Current country data
286
408
  country: MaskFull;
409
+
410
+ // Current locale used for country names
411
+ locale: string;
412
+
413
+ // Change country programmatically
287
414
  setCountry: (countryCode?: string | null) => boolean;
415
+
416
+ // Clear the input
288
417
  clear: () => void;
289
418
  }
290
419
  ```
@@ -300,6 +429,164 @@ interface UsePhoneMaskReturn {
300
429
  </script>
301
430
  ```
302
431
 
432
+ ## ⚡ Attachment API
433
+
434
+ The `phoneMaskAttachment` Svelte attachment (Svelte 5.29+) applies phone masking directly to any `<input>` element via `{@attach phoneMaskAttachment(...)}`. Unlike `use:` actions, the attachment factory re-runs reactively when reactive state in the call site changes — no manual `update()` needed.
435
+
436
+ ### Basic Usage
437
+
438
+ ```svelte
439
+ <script lang="ts">
440
+ import { phoneMaskAttachment } from '@desource/phone-mask-svelte';
441
+ </script>
442
+
443
+ <input {@attach phoneMaskAttachment('US')} />
444
+ ```
445
+
446
+ ### Options
447
+
448
+ ```ts
449
+ import type { PMaskFull, PMaskPhoneNumber } from '@desource/phone-mask-svelte';
450
+
451
+ interface PhoneMaskBindingOptions {
452
+ // Predefined country ISO code (e.g., 'US', 'DE', 'GB')
453
+ country?: string;
454
+
455
+ // Locale for country names (default: navigator.language)
456
+ locale?: string;
457
+
458
+ // Auto-detect country from IP/locale (default: false)
459
+ detect?: boolean;
460
+
461
+ // Value change callback
462
+ onChange?: (phone: PMaskPhoneNumber) => void;
463
+
464
+ // Country change callback
465
+ onCountryChange?: (country: PMaskFull) => void;
466
+ }
467
+ ```
468
+
469
+ The parameter can be a country code string (shorthand) or an options object:
470
+
471
+ ```svelte
472
+ <!-- Shorthand -->
473
+ <input {@attach phoneMaskAttachment('DE')} />
474
+
475
+ <!-- Full options -->
476
+ <input {@attach phoneMaskAttachment({ country: 'DE', onChange: handleChange })} />
477
+
478
+ <!-- Auto-detect -->
479
+ <input {@attach phoneMaskAttachment({ detect: true, onCountryChange: handleCountryChange })} />
480
+ ```
481
+
482
+ ### Reactive Country
483
+
484
+ Pass reactive state directly — the factory re-runs automatically when `selectedCountry` changes:
485
+
486
+ ```svelte
487
+ <script lang="ts">
488
+ import { phoneMaskAttachment as phoneMask } from '@desource/phone-mask-svelte';
489
+
490
+ let selectedCountry = $state('US');
491
+ let phoneData = $state<{ full: string; digits: string } | null>(null);
492
+ </script>
493
+
494
+ <select bind:value={selectedCountry}>
495
+ <option value="US">🇺🇸 United States</option>
496
+ <option value="GB">🇬🇧 United Kingdom</option>
497
+ <option value="DE">🇩🇪 Germany</option>
498
+ </select>
499
+
500
+ <input
501
+ {@attach phoneMask({ country: selectedCountry, onChange: (p) => (phoneData = p) })}
502
+ placeholder="Phone number"
503
+ />
504
+ ```
505
+
506
+ ## 🎬 Action API
507
+
508
+ The `phoneMaskAction` Svelte action applies phone masking directly to any `<input>` element via `use:phoneMaskAction`. It works with **all Svelte 5 versions** — no Svelte 5.29+ required.
509
+
510
+ When the bound parameter object changes (e.g. a new `country` value), Svelte automatically calls the action's `update()` hook, which re-applies the new options and switches the country if needed.
511
+
512
+ ### Basic Usage
513
+
514
+ ```svelte
515
+ <script lang="ts">
516
+ import { phoneMaskAction } from '@desource/phone-mask-svelte';
517
+ </script>
518
+
519
+ <input use:phoneMaskAction={'US'} />
520
+ ```
521
+
522
+ ### Options
523
+
524
+ ```ts
525
+ import type { PMaskFull, PMaskPhoneNumber } from '@desource/phone-mask-svelte';
526
+
527
+ interface PhoneMaskBindingOptions {
528
+ // Predefined country ISO code (e.g., 'US', 'DE', 'GB')
529
+ country?: string;
530
+
531
+ // Locale for country names (default: navigator.language)
532
+ locale?: string;
533
+
534
+ // Auto-detect country from GeoIP on mount; falls back to locale detection
535
+ detect?: boolean;
536
+
537
+ // Value change callback — fires on every phone number change
538
+ onChange?: (phone: PMaskPhoneNumber) => void;
539
+
540
+ // Country change callback — fires on initial mount and on country switch
541
+ onCountryChange?: (country: PMaskFull) => void;
542
+ }
543
+ ```
544
+
545
+ The parameter can be a country code string (shorthand) or an options object:
546
+
547
+ ```svelte
548
+ <!-- Shorthand -->
549
+ <input use:phoneMaskAction={'DE'} />
550
+
551
+ <!-- Full options -->
552
+ <input use:phoneMaskAction={{ country: 'DE', onChange: handleChange }} />
553
+
554
+ <!-- Auto-detect -->
555
+ <input use:phoneMaskAction={{ detect: true, onCountryChange: handleCountryChange }} />
556
+ ```
557
+
558
+ ### Reactive Country
559
+
560
+ Pass reactive `$state` inside the options object — Svelte calls `update()` automatically when `selectedCountry` changes:
561
+
562
+ ```svelte
563
+ <script lang="ts">
564
+ import { phoneMaskAction as phoneMask } from '@desource/phone-mask-svelte';
565
+
566
+ let selectedCountry = $state('US');
567
+ let phoneData = $state<{ full: string; digits: string } | null>(null);
568
+ </script>
569
+
570
+ <select bind:value={selectedCountry}>
571
+ <option value="US">🇺🇸 United States</option>
572
+ <option value="GB">🇬🇧 United Kingdom</option>
573
+ <option value="DE">🇩🇪 Germany</option>
574
+ </select>
575
+
576
+ <input
577
+ use:phoneMask={{ country: selectedCountry, onChange: (p) => (phoneData = p) }}
578
+ placeholder="Phone number"
579
+ />
580
+ ```
581
+
582
+ ### Action vs Attachment
583
+
584
+ | | `use:phoneMaskAction` | `{@attach phoneMaskAttachment(...)}` |
585
+ | ------------------------ | ----------------------------- | ------------------------------------ |
586
+ | Svelte version required | All Svelte 5 | Svelte 5.29+ |
587
+ | Reactivity mechanism | `update()` hook (auto-called) | Factory re-runs reactively |
588
+ | Manual `update()` needed | No (Svelte handles it) | No |
589
+
303
590
  ## 🎨 Component Styling
304
591
 
305
592
  ### CSS Custom Properties