@alikhalilll/a-tel-input 1.0.2 → 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/README.md +585 -72
- package/dist/_chunks/types.d.ts +661 -0
- package/dist/_chunks/types.js +52 -0
- package/dist/_chunks/types.js.map +1 -0
- package/dist/_chunks/usePhoneValidation.js +539 -0
- package/dist/_chunks/usePhoneValidation.js.map +1 -0
- package/dist/index.cjs +444 -683
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +122 -587
- package/dist/index.d.ts +122 -587
- package/dist/index.js +427 -646
- package/dist/index.js.map +1 -1
- package/dist/styles.css +3 -2
- package/dist/vee-validate/index.cjs +113 -0
- package/dist/vee-validate/index.cjs.map +1 -0
- package/dist/vee-validate/index.d.cts +86 -0
- package/dist/vee-validate/index.d.ts +86 -0
- package/dist/vee-validate/index.js +112 -0
- package/dist/vee-validate/index.js.map +1 -0
- package/dist/zod/index.cjs +211 -0
- package/dist/zod/index.cjs.map +1 -0
- package/dist/zod/index.d.cts +65 -0
- package/dist/zod/index.d.ts +65 -0
- package/dist/zod/index.js +208 -0
- package/dist/zod/index.js.map +1 -0
- package/package.json +33 -3
- package/src/components/ATelInput.vue +206 -66
- package/src/composables/useCountryDetection.ts +28 -11
- package/src/composables/useCountryMatching.ts +160 -20
- package/src/composables/useCountrySelection.ts +71 -0
- package/src/composables/usePhoneValidation.ts +81 -18
- package/src/composables/useSyncedModel.ts +80 -0
- package/src/composables/useTelInputValidation.ts +50 -11
- package/src/index.ts +2 -0
- package/src/types.ts +80 -0
- package/src/vee-validate/index.ts +2 -0
- package/src/vee-validate/useTelField.ts +202 -0
- package/src/zod/index.ts +259 -0
- package/web-types.json +44 -1
package/dist/styles.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */
|
|
2
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-outline-style:solid;--tw-ease:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}:root,:host{--spacing:.25rem;--ease-in:cubic-bezier(.4, 0, 1, 1);--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1)}.collapse{visibility:collapse}.flex{display:flex}.inline{display:inline}.table{display:table}.flex-shrink{flex-shrink:1}.ps-1{padding-inline-start:calc(var(--spacing) * 1)}.accent-foreground{accent-color:hsl(var(--ak-ui-foreground))}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.visible{visibility:visible}.sticky{position:sticky}.block{display:block}.hidden{display:none}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.border{border-style:var(--tw-border-style);border-width:1px}.text-popover-foreground{color:hsl(var(--ak-ui-popover-foreground))}@property --tw-ease{syntax:"*";inherits:false}.a-popover__overlay{z-index:50;pointer-events:auto;background:#000000b3;position:fixed;inset:0}.a-popover__overlay[data-state=open]{animation:.15s ease-out a-popover-overlay-in}.a-popover__overlay[data-state=closed]{animation:.1s ease-in forwards a-popover-overlay-out}@keyframes a-popover-overlay-in{0%{opacity:0}to{opacity:1}}@keyframes a-popover-overlay-out{0%{opacity:1}to{opacity:0}}@media (prefers-reduced-motion:reduce){.a-popover__overlay[data-state=open],.a-popover__overlay[data-state=closed]{animation:none}}.a-popover__content{z-index:60;border-radius:calc(var(--ak-ui-radius) - 2px);border:1px solid hsl(var(--ak-ui-border) / .7);background:hsl(var(--ak-ui-popover));width:18rem;color:hsl(var(--ak-ui-popover-foreground));outline:none;padding:1rem;box-shadow:0 20px 25px -5px #00000026,0 8px 10px -6px #00000026}.a-popover__content[data-state=open]{animation:.15s ease-out a-popover-in}.a-popover__content[data-state=closed]{animation:.1s ease-in forwards a-popover-out}@keyframes a-popover-in{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:scale(1)}}@keyframes a-popover-out{0%{opacity:1}to{opacity:0}}@media (prefers-reduced-motion:reduce){.a-popover__content[data-state=open],.a-popover__content[data-state=closed]{animation:none}}:root,.light{--ak-ui-background:0 0% 100%;--ak-ui-foreground:240 10% 3.9%;--ak-ui-card:0 0% 100%;--ak-ui-card-foreground:240 10% 3.9%;--ak-ui-popover:0 0% 100%;--ak-ui-popover-foreground:240 10% 3.9%;--ak-ui-primary:240 5.9% 10%;--ak-ui-primary-foreground:0 0% 98%;--ak-ui-secondary:240 4.8% 95.9%;--ak-ui-secondary-foreground:240 5.9% 10%;--ak-ui-muted:240 4.8% 95.9%;--ak-ui-muted-foreground:240 3.8% 46.1%;--ak-ui-accent:240 4.8% 95.9%;--ak-ui-accent-foreground:240 5.9% 10%;--ak-ui-destructive:0 84.2% 60.2%;--ak-ui-destructive-foreground:0 0% 98%;--ak-ui-border:240 5.9% 90%;--ak-ui-input:240 5.9% 90%;--ak-ui-ring:240 5.9% 10%;--ak-ui-radius:.5rem}.dark{--ak-ui-background:240 10% 3.9%;--ak-ui-foreground:0 0% 98%;--ak-ui-card:240 10% 3.9%;--ak-ui-card-foreground:0 0% 98%;--ak-ui-popover:240 10% 3.9%;--ak-ui-popover-foreground:0 0% 98%;--ak-ui-primary:0 0% 98%;--ak-ui-primary-foreground:240 5.9% 10%;--ak-ui-secondary:240 3.7% 15.9%;--ak-ui-secondary-foreground:0 0% 98%;--ak-ui-muted:240 3.7% 15.9%;--ak-ui-muted-foreground:240 5% 64.9%;--ak-ui-accent:240 3.7% 15.9%;--ak-ui-accent-foreground:0 0% 98%;--ak-ui-destructive:0 62.8% 30.6%;--ak-ui-destructive-foreground:0 0% 98%;--ak-ui-border:240 3.7% 15.9%;--ak-ui-input:240 3.7% 15.9%;--ak-ui-ring:240 4.9% 83.9%}:root,:host{--ease-in:cubic-bezier(.4, 0, 1, 1)}.text-foreground{color:hsl(var(--ak-ui-foreground))}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.ease-in{--tw-ease:var(--ease-in);transition-timing-function:var(--ease-in)}.a-drawer__overlay{z-index:40;background:#000000b3;position:fixed;inset:0}.a-drawer__overlay[data-state=open]{animation:.2s ease-out a-drawer-overlay-in}.a-drawer__overlay[data-state=closed]{animation:.15s ease-in forwards a-drawer-overlay-out}@keyframes a-drawer-overlay-in{0%{opacity:0}to{opacity:1}}@keyframes a-drawer-overlay-out{0%{opacity:1}to{opacity:0}}@media (prefers-reduced-motion:reduce){.a-drawer__overlay[data-state=open],.a-drawer__overlay[data-state=closed]{animation:none}}.a-drawer__content{z-index:50;background:hsl(var(--ak-ui-background));height:auto;color:hsl(var(--ak-ui-foreground));inset-inline:0;border-top-left-radius:10px;border-top-right-radius:10px;outline:none;flex-direction:column;margin-top:6rem;display:flex;position:fixed;bottom:0;box-shadow:0 25px 50px -12px #0000004d,0 12px 24px -8px #00000040}.a-drawer__handle{background:hsl(var(--ak-ui-muted));border-radius:999px;width:100px;height:.5rem;margin:1rem auto 0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-outline-style:solid;--tw-ease:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}:root,:host{--spacing:.25rem;--ease-in:cubic-bezier(.4, 0, 1, 1);--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1)}.collapse{visibility:collapse}.fixed{position:fixed}.static{position:static}.contents{display:contents}.flex{display:flex}.inline{display:inline}.table{display:table}.flex-shrink{flex-shrink:1}.ps-1{padding-inline-start:calc(var(--spacing) * 1)}.accent-foreground{accent-color:hsl(var(--ak-ui-foreground))}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.visible{visibility:visible}.sticky{position:sticky}.block{display:block}.hidden{display:none}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.border{border-style:var(--tw-border-style);border-width:1px}.text-popover-foreground{color:hsl(var(--ak-ui-popover-foreground))}@property --tw-ease{syntax:"*";inherits:false}.a-popover__overlay{z-index:50;pointer-events:auto;background:#000000b3;position:fixed;inset:0}.a-popover__overlay[data-state=open]{animation:.15s ease-out a-popover-overlay-in}.a-popover__overlay[data-state=closed]{animation:.1s ease-in forwards a-popover-overlay-out}@keyframes a-popover-overlay-in{0%{opacity:0}to{opacity:1}}@keyframes a-popover-overlay-out{0%{opacity:1}to{opacity:0}}@media (prefers-reduced-motion:reduce){.a-popover__overlay[data-state=open],.a-popover__overlay[data-state=closed]{animation:none}}.a-popover__content{z-index:60;border-radius:calc(var(--ak-ui-radius) - 2px);border:1px solid hsl(var(--ak-ui-border) / .7);background:hsl(var(--ak-ui-popover));width:18rem;color:hsl(var(--ak-ui-popover-foreground));outline:none;padding:1rem;box-shadow:0 20px 25px -5px #00000026,0 8px 10px -6px #00000026}.a-popover__content[data-state=open]{animation:.15s ease-out a-popover-in}.a-popover__content[data-state=closed]{animation:.1s ease-in forwards a-popover-out}@keyframes a-popover-in{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:scale(1)}}@keyframes a-popover-out{0%{opacity:1}to{opacity:0}}@media (prefers-reduced-motion:reduce){.a-popover__content[data-state=open],.a-popover__content[data-state=closed]{animation:none}}:root,.light{--ak-ui-background:0 0% 100%;--ak-ui-foreground:240 10% 3.9%;--ak-ui-card:0 0% 100%;--ak-ui-card-foreground:240 10% 3.9%;--ak-ui-popover:0 0% 100%;--ak-ui-popover-foreground:240 10% 3.9%;--ak-ui-primary:240 5.9% 10%;--ak-ui-primary-foreground:0 0% 98%;--ak-ui-secondary:240 4.8% 95.9%;--ak-ui-secondary-foreground:240 5.9% 10%;--ak-ui-muted:240 4.8% 95.9%;--ak-ui-muted-foreground:240 3.8% 46.1%;--ak-ui-accent:240 4.8% 95.9%;--ak-ui-accent-foreground:240 5.9% 10%;--ak-ui-destructive:0 84.2% 60.2%;--ak-ui-destructive-foreground:0 0% 98%;--ak-ui-border:240 5.9% 90%;--ak-ui-input:240 5.9% 90%;--ak-ui-ring:240 5.9% 10%;--ak-ui-radius:.5rem}.dark{--ak-ui-background:240 10% 3.9%;--ak-ui-foreground:0 0% 98%;--ak-ui-card:240 10% 3.9%;--ak-ui-card-foreground:0 0% 98%;--ak-ui-popover:240 10% 3.9%;--ak-ui-popover-foreground:0 0% 98%;--ak-ui-primary:0 0% 98%;--ak-ui-primary-foreground:240 5.9% 10%;--ak-ui-secondary:240 3.7% 15.9%;--ak-ui-secondary-foreground:0 0% 98%;--ak-ui-muted:240 3.7% 15.9%;--ak-ui-muted-foreground:240 5% 64.9%;--ak-ui-accent:240 3.7% 15.9%;--ak-ui-accent-foreground:0 0% 98%;--ak-ui-destructive:0 62.8% 30.6%;--ak-ui-destructive-foreground:0 0% 98%;--ak-ui-border:240 3.7% 15.9%;--ak-ui-input:240 3.7% 15.9%;--ak-ui-ring:240 4.9% 83.9%}:root,:host{--ease-in:cubic-bezier(.4, 0, 1, 1)}.text-foreground{color:hsl(var(--ak-ui-foreground))}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.ease-in{--tw-ease:var(--ease-in);transition-timing-function:var(--ease-in)}.a-drawer__overlay{z-index:40;background:#000000b3;position:fixed;inset:0}.a-drawer__overlay[data-state=open]{animation:.2s ease-out a-drawer-overlay-in}.a-drawer__overlay[data-state=closed]{animation:.15s ease-in forwards a-drawer-overlay-out}@keyframes a-drawer-overlay-in{0%{opacity:0}to{opacity:1}}@keyframes a-drawer-overlay-out{0%{opacity:1}to{opacity:0}}@media (prefers-reduced-motion:reduce){.a-drawer__overlay[data-state=open],.a-drawer__overlay[data-state=closed]{animation:none}}.a-drawer__content{z-index:50;background:hsl(var(--ak-ui-background));height:auto;color:hsl(var(--ak-ui-foreground));inset-inline:0;border-top-left-radius:10px;border-top-right-radius:10px;outline:none;flex-direction:column;margin-top:6rem;display:flex;position:fixed;bottom:0;box-shadow:0 25px 50px -12px #0000004d,0 12px 24px -8px #00000040}.a-drawer__handle{background:hsl(var(--ak-ui-muted));border-radius:999px;width:100px;height:.5rem;margin:1rem auto 0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}
|
|
3
3
|
/* --- bundled SFC styles --- */
|
|
4
4
|
|
|
5
5
|
.a-country-flag[data-v-705c2224] {
|
|
@@ -411,7 +411,8 @@ to {
|
|
|
411
411
|
.a-tel-input__input[data-has-dial][data-v-8305dc81] {
|
|
412
412
|
padding-inline-start: 0.25rem;
|
|
413
413
|
}
|
|
414
|
-
.a-tel-input__detecting[data-v-8305dc81]
|
|
414
|
+
.a-tel-input__detecting[data-v-8305dc81],
|
|
415
|
+
.a-tel-input__validating[data-v-8305dc81] {
|
|
415
416
|
display: inline-flex;
|
|
416
417
|
height: 100%;
|
|
417
418
|
flex-shrink: 0;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_usePhoneValidation = require("../_chunks/usePhoneValidation.js");
|
|
3
|
+
let vue = require("vue");
|
|
4
|
+
let vee_validate = require("vee-validate");
|
|
5
|
+
//#region src/vee-validate/useTelField.ts
|
|
6
|
+
/**
|
|
7
|
+
* VeeValidate adapter for `@alikhalilll/a-tel-input`.
|
|
8
|
+
*
|
|
9
|
+
* `useTelField()` owns the two v-models (`phone` + `country`) and the canonical
|
|
10
|
+
* E.164 string used by VeeValidate / Zod / yup, and returns a single ready-to-bind
|
|
11
|
+
* object so a consumer doesn't have to glue the pieces together.
|
|
12
|
+
*
|
|
13
|
+
* Quick start:
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { useTelField } from '@alikhalilll/a-tel-input/vee-validate';
|
|
17
|
+
* import { toTypedSchema } from '@vee-validate/zod';
|
|
18
|
+
* import { z } from 'zod';
|
|
19
|
+
* import { zPhone } from '@alikhalilll/a-tel-input/zod';
|
|
20
|
+
*
|
|
21
|
+
* const { phone, country, error, handleBlur, fieldProps } = useTelField('phone', {
|
|
22
|
+
* rules: toTypedSchema(zPhone()),
|
|
23
|
+
* validateOn: 'blur',
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* ```vue
|
|
28
|
+
* <ATelInput
|
|
29
|
+
* v-model:phone="phone"
|
|
30
|
+
* v-model:country="country"
|
|
31
|
+
* v-bind="fieldProps"
|
|
32
|
+
* @blur="handleBlur"
|
|
33
|
+
* />
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* Server-side validation (e.g. "does this phone already exist?") plugs in via the
|
|
37
|
+
* `rules` callback — VeeValidate already supports async rules:
|
|
38
|
+
*
|
|
39
|
+
* ```ts
|
|
40
|
+
* const { phone, country, error, handleBlur, fieldProps, validating } = useTelField('phone', {
|
|
41
|
+
* rules: async (value: string) => {
|
|
42
|
+
* const sync = await zPhone().safeParseAsync(value);
|
|
43
|
+
* if (!sync.success) return sync.error.issues[0]!.message;
|
|
44
|
+
* const res = await $fetch('/api/phone/exists', { query: { phone: value } });
|
|
45
|
+
* return res.exists ? 'This phone is already registered.' : true;
|
|
46
|
+
* },
|
|
47
|
+
* validateOn: 'blur',
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* The `validating` ref is `true` while VeeValidate's async pipeline is in flight —
|
|
52
|
+
* bind it to ATelInput's `:validating` prop to surface a spinner inside the field.
|
|
53
|
+
*
|
|
54
|
+
* `vee-validate` is an **optional peer dependency** — install it yourself in your app.
|
|
55
|
+
*/
|
|
56
|
+
/**
|
|
57
|
+
* Register a phone field with VeeValidate. See file header for usage examples.
|
|
58
|
+
*
|
|
59
|
+
* @param name The field name (used by VeeValidate, also forwarded to the inner
|
|
60
|
+
* `<input name="">` for native form submission).
|
|
61
|
+
* @param options See {@link UseTelFieldOptions}.
|
|
62
|
+
*/
|
|
63
|
+
function useTelField(name, options = {}) {
|
|
64
|
+
const phone = (0, vue.ref)(options.initialPhone ?? "");
|
|
65
|
+
const country = (0, vue.ref)(options.initialCountry ?? null);
|
|
66
|
+
const v = require_usePhoneValidation.usePhoneValidation();
|
|
67
|
+
v.getCountries();
|
|
68
|
+
function composeE164() {
|
|
69
|
+
if (!phone.value) return "";
|
|
70
|
+
const dial = country.value;
|
|
71
|
+
if (dial == null) return "";
|
|
72
|
+
const iso2 = v.getCountriesByDial(String(dial))[0]?.value;
|
|
73
|
+
if (!iso2) return "";
|
|
74
|
+
return v.validate({
|
|
75
|
+
country: { iso2 },
|
|
76
|
+
phone: phone.value
|
|
77
|
+
}).full_phone ?? "";
|
|
78
|
+
}
|
|
79
|
+
const initialValue = composeE164();
|
|
80
|
+
const field = (0, vee_validate.useField)(name, options.rules, {
|
|
81
|
+
initialValue,
|
|
82
|
+
validateOnValueUpdate: false,
|
|
83
|
+
...options.fieldOptions
|
|
84
|
+
});
|
|
85
|
+
(0, vue.watch)([phone, country], () => {
|
|
86
|
+
field.value.value = composeE164();
|
|
87
|
+
}, { flush: "post" });
|
|
88
|
+
const validating = (0, vue.computed)(() => !!field.meta.pending);
|
|
89
|
+
const fieldProps = (0, vue.computed)(() => ({
|
|
90
|
+
name: (0, vue.toValue)(name),
|
|
91
|
+
error: field.errorMessage.value ?? null,
|
|
92
|
+
validateOn: options.validateOn ?? "blur",
|
|
93
|
+
validating: validating.value,
|
|
94
|
+
defaultCountry: options.defaultCountry
|
|
95
|
+
}));
|
|
96
|
+
return {
|
|
97
|
+
phone,
|
|
98
|
+
country,
|
|
99
|
+
e164: (0, vue.computed)(() => field.value.value ?? ""),
|
|
100
|
+
error: field.errorMessage,
|
|
101
|
+
validating,
|
|
102
|
+
meta: field.meta,
|
|
103
|
+
handleBlur: field.handleBlur,
|
|
104
|
+
validate: field.validate,
|
|
105
|
+
setErrors: field.setErrors,
|
|
106
|
+
resetField: field.resetField,
|
|
107
|
+
fieldProps
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
exports.useTelField = useTelField;
|
|
112
|
+
|
|
113
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["usePhoneValidation"],"sources":["../../src/vee-validate/useTelField.ts"],"sourcesContent":["/**\n * VeeValidate adapter for `@alikhalilll/a-tel-input`.\n *\n * `useTelField()` owns the two v-models (`phone` + `country`) and the canonical\n * E.164 string used by VeeValidate / Zod / yup, and returns a single ready-to-bind\n * object so a consumer doesn't have to glue the pieces together.\n *\n * Quick start:\n *\n * ```ts\n * import { useTelField } from '@alikhalilll/a-tel-input/vee-validate';\n * import { toTypedSchema } from '@vee-validate/zod';\n * import { z } from 'zod';\n * import { zPhone } from '@alikhalilll/a-tel-input/zod';\n *\n * const { phone, country, error, handleBlur, fieldProps } = useTelField('phone', {\n * rules: toTypedSchema(zPhone()),\n * validateOn: 'blur',\n * });\n * ```\n *\n * ```vue\n * <ATelInput\n * v-model:phone=\"phone\"\n * v-model:country=\"country\"\n * v-bind=\"fieldProps\"\n * @blur=\"handleBlur\"\n * />\n * ```\n *\n * Server-side validation (e.g. \"does this phone already exist?\") plugs in via the\n * `rules` callback — VeeValidate already supports async rules:\n *\n * ```ts\n * const { phone, country, error, handleBlur, fieldProps, validating } = useTelField('phone', {\n * rules: async (value: string) => {\n * const sync = await zPhone().safeParseAsync(value);\n * if (!sync.success) return sync.error.issues[0]!.message;\n * const res = await $fetch('/api/phone/exists', { query: { phone: value } });\n * return res.exists ? 'This phone is already registered.' : true;\n * },\n * validateOn: 'blur',\n * });\n * ```\n *\n * The `validating` ref is `true` while VeeValidate's async pipeline is in flight —\n * bind it to ATelInput's `:validating` prop to surface a spinner inside the field.\n *\n * `vee-validate` is an **optional peer dependency** — install it yourself in your app.\n */\n\nimport { computed, ref, watch, type ComputedRef, type MaybeRefOrGetter } from 'vue';\nimport { toValue } from 'vue';\nimport { useField, type FieldOptions, type RuleExpression } from 'vee-validate';\nimport { usePhoneValidation } from '../composables/usePhoneValidation';\nimport type { ATelInputValidateOn } from '../composables/useTelInputValidation';\n\nexport interface UseTelFieldOptions {\n /**\n * VeeValidate rules — a function, schema, or string. Use when the field stands\n * alone (no `useForm` / no form-level `validationSchema`).\n *\n * **Important**: vee-validate **ignores field-level `rules` whenever the parent\n * `useForm` is configured with `validationSchema`**. If you need async / server-\n * side validation inside a form, chain it onto the form schema via\n * `z.refine(async)` instead — that's what `handleSubmit` actually awaits and what\n * drives this composable's `validating` ref (via `meta.pending`). See the README\n * section \"Server-side validation\" for the full pattern.\n */\n rules?: RuleExpression<string>;\n /**\n * Initial digits-only national number, e.g. `'1066105963'`. Defaults to `''`.\n */\n initialPhone?: string;\n /**\n * Initial dial-digit number, e.g. `20` for Egypt. Defaults to `null`.\n */\n initialCountry?: number | null;\n /**\n * Default country (ISO2 like `'EG'` or dial code like `'20'`). Forwarded as the\n * `defaultCountry` prop on `<ATelInput>` via `fieldProps`.\n */\n defaultCountry?: string;\n /**\n * When to surface validation in the UI. Defaults to `'blur'` (the typical form-library\n * UX). Forwarded as the `validateOn` prop on `<ATelInput>` via `fieldProps`.\n */\n validateOn?: ATelInputValidateOn;\n /**\n * Forwarded to `useField` — extra options passed verbatim to VeeValidate. Use to\n * configure `keepValueOnUnmount`, `syncVModel`, etc.\n */\n fieldOptions?: Omit<FieldOptions<string>, 'initialValue'>;\n}\n\nexport interface UseTelFieldReturn {\n /** `v-model:phone` source — digits-only national number. Bind to `<ATelInput>`. */\n phone: import('vue').Ref<string>;\n /** `v-model:country` source — dial-digit number (e.g., `20`). Bind to `<ATelInput>`. */\n country: import('vue').Ref<number | null>;\n /** The canonical E.164 string fed to VeeValidate's schema (read-only). */\n e164: ComputedRef<string>;\n /** Current validation error message, or `undefined` when valid. From `useField`. */\n error: import('vue').Ref<string | undefined>;\n /** `true` while VeeValidate is running an async rule (e.g. server-side check). */\n validating: ComputedRef<boolean>;\n /** Whether the field has been blurred / dirtied / submitted (from VeeValidate `meta`). */\n meta: ReturnType<typeof useField<string>>['meta'];\n /** Forward this to `<ATelInput @blur=\"handleBlur\">` so VeeValidate's blur trigger fires. */\n handleBlur: ReturnType<typeof useField<string>>['handleBlur'];\n /** Imperatively trigger validation (e.g., after a programmatic value change). */\n validate: ReturnType<typeof useField<string>>['validate'];\n /** Imperatively set the error message — useful for server errors not raised by `rules`. */\n setErrors: ReturnType<typeof useField<string>>['setErrors'];\n /** Reset the field to its initial state. */\n resetField: ReturnType<typeof useField<string>>['resetField'];\n /**\n * Ready-to-bind prop bag for `<ATelInput v-bind=\"fieldProps\">`. Carries `name`,\n * `error`, `validateOn`, `validating`, and `defaultCountry`.\n */\n fieldProps: ComputedRef<{\n name: string;\n error: string | null;\n validateOn: ATelInputValidateOn;\n validating: boolean;\n defaultCountry?: string;\n }>;\n}\n\n/**\n * Register a phone field with VeeValidate. See file header for usage examples.\n *\n * @param name The field name (used by VeeValidate, also forwarded to the inner\n * `<input name=\"\">` for native form submission).\n * @param options See {@link UseTelFieldOptions}.\n */\nexport function useTelField(\n name: MaybeRefOrGetter<string>,\n options: UseTelFieldOptions = {}\n): UseTelFieldReturn {\n const phone = ref<string>(options.initialPhone ?? '');\n const country = ref<number | null>(options.initialCountry ?? null);\n\n const v = usePhoneValidation();\n void v.getCountries();\n\n // Compose E.164 from the two v-models — this is the canonical value VeeValidate\n // tracks. NANP (`+1`) resolves to `'US'` for validation; libphonenumber-js applies\n // the same rule set to every NANP country so this is correct.\n function composeE164(): string {\n if (!phone.value) return '';\n const dial = country.value;\n if (dial == null) return '';\n const matches = v.getCountriesByDial(String(dial));\n const iso2 = matches[0]?.value;\n if (!iso2) return '';\n const res = v.validate({ country: { iso2 }, phone: phone.value });\n return res.full_phone ?? '';\n }\n\n const initialValue = composeE164();\n\n const field = useField<string>(name, options.rules, {\n initialValue,\n // Don't run rules on every keystroke — let validateOn drive when validation fires.\n validateOnValueUpdate: false,\n ...options.fieldOptions,\n });\n\n // Keep VeeValidate's value in sync with the two v-models.\n watch(\n [phone, country],\n () => {\n field.value.value = composeE164();\n },\n { flush: 'post' }\n );\n\n const validating = computed(() => !!field.meta.pending);\n\n const fieldProps = computed(() => ({\n name: toValue(name),\n error: (field.errorMessage.value ?? null) as string | null,\n validateOn: options.validateOn ?? ('blur' as ATelInputValidateOn),\n validating: validating.value,\n defaultCountry: options.defaultCountry,\n }));\n\n return {\n phone,\n country,\n e164: computed(() => field.value.value ?? ''),\n error: field.errorMessage,\n validating,\n meta: field.meta,\n handleBlur: field.handleBlur,\n validate: field.validate,\n setErrors: field.setErrors,\n resetField: field.resetField,\n fieldProps,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwIA,SAAgB,YACd,MACA,UAA8B,CAAC,GACZ;CACnB,MAAM,SAAA,GAAA,IAAA,KAAoB,QAAQ,gBAAgB,EAAE;CACpD,MAAM,WAAA,GAAA,IAAA,KAA6B,QAAQ,kBAAkB,IAAI;CAEjE,MAAM,IAAIA,2BAAAA,mBAAmB;CAC7B,EAAO,aAAa;CAKpB,SAAS,cAAsB;EAC7B,IAAI,CAAC,MAAM,OAAO,OAAO;EACzB,MAAM,OAAO,QAAQ;EACrB,IAAI,QAAQ,MAAM,OAAO;EAEzB,MAAM,OADU,EAAE,mBAAmB,OAAO,IAAI,CAC7B,EAAE,IAAI;EACzB,IAAI,CAAC,MAAM,OAAO;EAElB,OADY,EAAE,SAAS;GAAE,SAAS,EAAE,KAAK;GAAG,OAAO,MAAM;EAAM,CACtD,EAAE,cAAc;CAC3B;CAEA,MAAM,eAAe,YAAY;CAEjC,MAAM,SAAA,GAAA,aAAA,UAAyB,MAAM,QAAQ,OAAO;EAClD;EAEA,uBAAuB;EACvB,GAAG,QAAQ;CACb,CAAC;CAGD,CAAA,GAAA,IAAA,OACE,CAAC,OAAO,OAAO,SACT;EACJ,MAAM,MAAM,QAAQ,YAAY;CAClC,GACA,EAAE,OAAO,OAAO,CAClB;CAEA,MAAM,cAAA,GAAA,IAAA,gBAA4B,CAAC,CAAC,MAAM,KAAK,OAAO;CAEtD,MAAM,cAAA,GAAA,IAAA,iBAA6B;EACjC,OAAA,GAAA,IAAA,SAAc,IAAI;EAClB,OAAQ,MAAM,aAAa,SAAS;EACpC,YAAY,QAAQ,cAAe;EACnC,YAAY,WAAW;EACvB,gBAAgB,QAAQ;CAC1B,EAAE;CAEF,OAAO;EACL;EACA;EACA,OAAA,GAAA,IAAA,gBAAqB,MAAM,MAAM,SAAS,EAAE;EAC5C,OAAO,MAAM;EACb;EACA,MAAM,MAAM;EACZ,YAAY,MAAM;EAClB,UAAU,MAAM;EAChB,WAAW,MAAM;EACjB,YAAY,MAAM;EAClB;CACF;AACF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { b as ATelInputValidateOn } from "../_chunks/types.js";
|
|
2
|
+
import { ComputedRef, MaybeRefOrGetter } from "vue";
|
|
3
|
+
import { FieldOptions, RuleExpression, useField } from "vee-validate";
|
|
4
|
+
|
|
5
|
+
//#region src/vee-validate/useTelField.d.ts
|
|
6
|
+
interface UseTelFieldOptions {
|
|
7
|
+
/**
|
|
8
|
+
* VeeValidate rules — a function, schema, or string. Use when the field stands
|
|
9
|
+
* alone (no `useForm` / no form-level `validationSchema`).
|
|
10
|
+
*
|
|
11
|
+
* **Important**: vee-validate **ignores field-level `rules` whenever the parent
|
|
12
|
+
* `useForm` is configured with `validationSchema`**. If you need async / server-
|
|
13
|
+
* side validation inside a form, chain it onto the form schema via
|
|
14
|
+
* `z.refine(async)` instead — that's what `handleSubmit` actually awaits and what
|
|
15
|
+
* drives this composable's `validating` ref (via `meta.pending`). See the README
|
|
16
|
+
* section "Server-side validation" for the full pattern.
|
|
17
|
+
*/
|
|
18
|
+
rules?: RuleExpression<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Initial digits-only national number, e.g. `'1066105963'`. Defaults to `''`.
|
|
21
|
+
*/
|
|
22
|
+
initialPhone?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Initial dial-digit number, e.g. `20` for Egypt. Defaults to `null`.
|
|
25
|
+
*/
|
|
26
|
+
initialCountry?: number | null;
|
|
27
|
+
/**
|
|
28
|
+
* Default country (ISO2 like `'EG'` or dial code like `'20'`). Forwarded as the
|
|
29
|
+
* `defaultCountry` prop on `<ATelInput>` via `fieldProps`.
|
|
30
|
+
*/
|
|
31
|
+
defaultCountry?: string;
|
|
32
|
+
/**
|
|
33
|
+
* When to surface validation in the UI. Defaults to `'blur'` (the typical form-library
|
|
34
|
+
* UX). Forwarded as the `validateOn` prop on `<ATelInput>` via `fieldProps`.
|
|
35
|
+
*/
|
|
36
|
+
validateOn?: ATelInputValidateOn;
|
|
37
|
+
/**
|
|
38
|
+
* Forwarded to `useField` — extra options passed verbatim to VeeValidate. Use to
|
|
39
|
+
* configure `keepValueOnUnmount`, `syncVModel`, etc.
|
|
40
|
+
*/
|
|
41
|
+
fieldOptions?: Omit<FieldOptions<string>, 'initialValue'>;
|
|
42
|
+
}
|
|
43
|
+
interface UseTelFieldReturn {
|
|
44
|
+
/** `v-model:phone` source — digits-only national number. Bind to `<ATelInput>`. */
|
|
45
|
+
phone: import('vue').Ref<string>;
|
|
46
|
+
/** `v-model:country` source — dial-digit number (e.g., `20`). Bind to `<ATelInput>`. */
|
|
47
|
+
country: import('vue').Ref<number | null>;
|
|
48
|
+
/** The canonical E.164 string fed to VeeValidate's schema (read-only). */
|
|
49
|
+
e164: ComputedRef<string>;
|
|
50
|
+
/** Current validation error message, or `undefined` when valid. From `useField`. */
|
|
51
|
+
error: import('vue').Ref<string | undefined>;
|
|
52
|
+
/** `true` while VeeValidate is running an async rule (e.g. server-side check). */
|
|
53
|
+
validating: ComputedRef<boolean>;
|
|
54
|
+
/** Whether the field has been blurred / dirtied / submitted (from VeeValidate `meta`). */
|
|
55
|
+
meta: ReturnType<typeof useField<string>>['meta'];
|
|
56
|
+
/** Forward this to `<ATelInput @blur="handleBlur">` so VeeValidate's blur trigger fires. */
|
|
57
|
+
handleBlur: ReturnType<typeof useField<string>>['handleBlur'];
|
|
58
|
+
/** Imperatively trigger validation (e.g., after a programmatic value change). */
|
|
59
|
+
validate: ReturnType<typeof useField<string>>['validate'];
|
|
60
|
+
/** Imperatively set the error message — useful for server errors not raised by `rules`. */
|
|
61
|
+
setErrors: ReturnType<typeof useField<string>>['setErrors'];
|
|
62
|
+
/** Reset the field to its initial state. */
|
|
63
|
+
resetField: ReturnType<typeof useField<string>>['resetField'];
|
|
64
|
+
/**
|
|
65
|
+
* Ready-to-bind prop bag for `<ATelInput v-bind="fieldProps">`. Carries `name`,
|
|
66
|
+
* `error`, `validateOn`, `validating`, and `defaultCountry`.
|
|
67
|
+
*/
|
|
68
|
+
fieldProps: ComputedRef<{
|
|
69
|
+
name: string;
|
|
70
|
+
error: string | null;
|
|
71
|
+
validateOn: ATelInputValidateOn;
|
|
72
|
+
validating: boolean;
|
|
73
|
+
defaultCountry?: string;
|
|
74
|
+
}>;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Register a phone field with VeeValidate. See file header for usage examples.
|
|
78
|
+
*
|
|
79
|
+
* @param name The field name (used by VeeValidate, also forwarded to the inner
|
|
80
|
+
* `<input name="">` for native form submission).
|
|
81
|
+
* @param options See {@link UseTelFieldOptions}.
|
|
82
|
+
*/
|
|
83
|
+
declare function useTelField(name: MaybeRefOrGetter<string>, options?: UseTelFieldOptions): UseTelFieldReturn;
|
|
84
|
+
//#endregion
|
|
85
|
+
export { type UseTelFieldOptions, type UseTelFieldReturn, useTelField };
|
|
86
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { b as ATelInputValidateOn } from "../_chunks/types.js";
|
|
2
|
+
import { ComputedRef, MaybeRefOrGetter } from "vue";
|
|
3
|
+
import { FieldOptions, RuleExpression, useField } from "vee-validate";
|
|
4
|
+
|
|
5
|
+
//#region src/vee-validate/useTelField.d.ts
|
|
6
|
+
interface UseTelFieldOptions {
|
|
7
|
+
/**
|
|
8
|
+
* VeeValidate rules — a function, schema, or string. Use when the field stands
|
|
9
|
+
* alone (no `useForm` / no form-level `validationSchema`).
|
|
10
|
+
*
|
|
11
|
+
* **Important**: vee-validate **ignores field-level `rules` whenever the parent
|
|
12
|
+
* `useForm` is configured with `validationSchema`**. If you need async / server-
|
|
13
|
+
* side validation inside a form, chain it onto the form schema via
|
|
14
|
+
* `z.refine(async)` instead — that's what `handleSubmit` actually awaits and what
|
|
15
|
+
* drives this composable's `validating` ref (via `meta.pending`). See the README
|
|
16
|
+
* section "Server-side validation" for the full pattern.
|
|
17
|
+
*/
|
|
18
|
+
rules?: RuleExpression<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Initial digits-only national number, e.g. `'1066105963'`. Defaults to `''`.
|
|
21
|
+
*/
|
|
22
|
+
initialPhone?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Initial dial-digit number, e.g. `20` for Egypt. Defaults to `null`.
|
|
25
|
+
*/
|
|
26
|
+
initialCountry?: number | null;
|
|
27
|
+
/**
|
|
28
|
+
* Default country (ISO2 like `'EG'` or dial code like `'20'`). Forwarded as the
|
|
29
|
+
* `defaultCountry` prop on `<ATelInput>` via `fieldProps`.
|
|
30
|
+
*/
|
|
31
|
+
defaultCountry?: string;
|
|
32
|
+
/**
|
|
33
|
+
* When to surface validation in the UI. Defaults to `'blur'` (the typical form-library
|
|
34
|
+
* UX). Forwarded as the `validateOn` prop on `<ATelInput>` via `fieldProps`.
|
|
35
|
+
*/
|
|
36
|
+
validateOn?: ATelInputValidateOn;
|
|
37
|
+
/**
|
|
38
|
+
* Forwarded to `useField` — extra options passed verbatim to VeeValidate. Use to
|
|
39
|
+
* configure `keepValueOnUnmount`, `syncVModel`, etc.
|
|
40
|
+
*/
|
|
41
|
+
fieldOptions?: Omit<FieldOptions<string>, 'initialValue'>;
|
|
42
|
+
}
|
|
43
|
+
interface UseTelFieldReturn {
|
|
44
|
+
/** `v-model:phone` source — digits-only national number. Bind to `<ATelInput>`. */
|
|
45
|
+
phone: import('vue').Ref<string>;
|
|
46
|
+
/** `v-model:country` source — dial-digit number (e.g., `20`). Bind to `<ATelInput>`. */
|
|
47
|
+
country: import('vue').Ref<number | null>;
|
|
48
|
+
/** The canonical E.164 string fed to VeeValidate's schema (read-only). */
|
|
49
|
+
e164: ComputedRef<string>;
|
|
50
|
+
/** Current validation error message, or `undefined` when valid. From `useField`. */
|
|
51
|
+
error: import('vue').Ref<string | undefined>;
|
|
52
|
+
/** `true` while VeeValidate is running an async rule (e.g. server-side check). */
|
|
53
|
+
validating: ComputedRef<boolean>;
|
|
54
|
+
/** Whether the field has been blurred / dirtied / submitted (from VeeValidate `meta`). */
|
|
55
|
+
meta: ReturnType<typeof useField<string>>['meta'];
|
|
56
|
+
/** Forward this to `<ATelInput @blur="handleBlur">` so VeeValidate's blur trigger fires. */
|
|
57
|
+
handleBlur: ReturnType<typeof useField<string>>['handleBlur'];
|
|
58
|
+
/** Imperatively trigger validation (e.g., after a programmatic value change). */
|
|
59
|
+
validate: ReturnType<typeof useField<string>>['validate'];
|
|
60
|
+
/** Imperatively set the error message — useful for server errors not raised by `rules`. */
|
|
61
|
+
setErrors: ReturnType<typeof useField<string>>['setErrors'];
|
|
62
|
+
/** Reset the field to its initial state. */
|
|
63
|
+
resetField: ReturnType<typeof useField<string>>['resetField'];
|
|
64
|
+
/**
|
|
65
|
+
* Ready-to-bind prop bag for `<ATelInput v-bind="fieldProps">`. Carries `name`,
|
|
66
|
+
* `error`, `validateOn`, `validating`, and `defaultCountry`.
|
|
67
|
+
*/
|
|
68
|
+
fieldProps: ComputedRef<{
|
|
69
|
+
name: string;
|
|
70
|
+
error: string | null;
|
|
71
|
+
validateOn: ATelInputValidateOn;
|
|
72
|
+
validating: boolean;
|
|
73
|
+
defaultCountry?: string;
|
|
74
|
+
}>;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Register a phone field with VeeValidate. See file header for usage examples.
|
|
78
|
+
*
|
|
79
|
+
* @param name The field name (used by VeeValidate, also forwarded to the inner
|
|
80
|
+
* `<input name="">` for native form submission).
|
|
81
|
+
* @param options See {@link UseTelFieldOptions}.
|
|
82
|
+
*/
|
|
83
|
+
declare function useTelField(name: MaybeRefOrGetter<string>, options?: UseTelFieldOptions): UseTelFieldReturn;
|
|
84
|
+
//#endregion
|
|
85
|
+
export { type UseTelFieldOptions, type UseTelFieldReturn, useTelField };
|
|
86
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { n as usePhoneValidation } from "../_chunks/usePhoneValidation.js";
|
|
2
|
+
import { computed, ref, toValue, watch } from "vue";
|
|
3
|
+
import { useField } from "vee-validate";
|
|
4
|
+
//#region src/vee-validate/useTelField.ts
|
|
5
|
+
/**
|
|
6
|
+
* VeeValidate adapter for `@alikhalilll/a-tel-input`.
|
|
7
|
+
*
|
|
8
|
+
* `useTelField()` owns the two v-models (`phone` + `country`) and the canonical
|
|
9
|
+
* E.164 string used by VeeValidate / Zod / yup, and returns a single ready-to-bind
|
|
10
|
+
* object so a consumer doesn't have to glue the pieces together.
|
|
11
|
+
*
|
|
12
|
+
* Quick start:
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { useTelField } from '@alikhalilll/a-tel-input/vee-validate';
|
|
16
|
+
* import { toTypedSchema } from '@vee-validate/zod';
|
|
17
|
+
* import { z } from 'zod';
|
|
18
|
+
* import { zPhone } from '@alikhalilll/a-tel-input/zod';
|
|
19
|
+
*
|
|
20
|
+
* const { phone, country, error, handleBlur, fieldProps } = useTelField('phone', {
|
|
21
|
+
* rules: toTypedSchema(zPhone()),
|
|
22
|
+
* validateOn: 'blur',
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* ```vue
|
|
27
|
+
* <ATelInput
|
|
28
|
+
* v-model:phone="phone"
|
|
29
|
+
* v-model:country="country"
|
|
30
|
+
* v-bind="fieldProps"
|
|
31
|
+
* @blur="handleBlur"
|
|
32
|
+
* />
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* Server-side validation (e.g. "does this phone already exist?") plugs in via the
|
|
36
|
+
* `rules` callback — VeeValidate already supports async rules:
|
|
37
|
+
*
|
|
38
|
+
* ```ts
|
|
39
|
+
* const { phone, country, error, handleBlur, fieldProps, validating } = useTelField('phone', {
|
|
40
|
+
* rules: async (value: string) => {
|
|
41
|
+
* const sync = await zPhone().safeParseAsync(value);
|
|
42
|
+
* if (!sync.success) return sync.error.issues[0]!.message;
|
|
43
|
+
* const res = await $fetch('/api/phone/exists', { query: { phone: value } });
|
|
44
|
+
* return res.exists ? 'This phone is already registered.' : true;
|
|
45
|
+
* },
|
|
46
|
+
* validateOn: 'blur',
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* The `validating` ref is `true` while VeeValidate's async pipeline is in flight —
|
|
51
|
+
* bind it to ATelInput's `:validating` prop to surface a spinner inside the field.
|
|
52
|
+
*
|
|
53
|
+
* `vee-validate` is an **optional peer dependency** — install it yourself in your app.
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* Register a phone field with VeeValidate. See file header for usage examples.
|
|
57
|
+
*
|
|
58
|
+
* @param name The field name (used by VeeValidate, also forwarded to the inner
|
|
59
|
+
* `<input name="">` for native form submission).
|
|
60
|
+
* @param options See {@link UseTelFieldOptions}.
|
|
61
|
+
*/
|
|
62
|
+
function useTelField(name, options = {}) {
|
|
63
|
+
const phone = ref(options.initialPhone ?? "");
|
|
64
|
+
const country = ref(options.initialCountry ?? null);
|
|
65
|
+
const v = usePhoneValidation();
|
|
66
|
+
v.getCountries();
|
|
67
|
+
function composeE164() {
|
|
68
|
+
if (!phone.value) return "";
|
|
69
|
+
const dial = country.value;
|
|
70
|
+
if (dial == null) return "";
|
|
71
|
+
const iso2 = v.getCountriesByDial(String(dial))[0]?.value;
|
|
72
|
+
if (!iso2) return "";
|
|
73
|
+
return v.validate({
|
|
74
|
+
country: { iso2 },
|
|
75
|
+
phone: phone.value
|
|
76
|
+
}).full_phone ?? "";
|
|
77
|
+
}
|
|
78
|
+
const initialValue = composeE164();
|
|
79
|
+
const field = useField(name, options.rules, {
|
|
80
|
+
initialValue,
|
|
81
|
+
validateOnValueUpdate: false,
|
|
82
|
+
...options.fieldOptions
|
|
83
|
+
});
|
|
84
|
+
watch([phone, country], () => {
|
|
85
|
+
field.value.value = composeE164();
|
|
86
|
+
}, { flush: "post" });
|
|
87
|
+
const validating = computed(() => !!field.meta.pending);
|
|
88
|
+
const fieldProps = computed(() => ({
|
|
89
|
+
name: toValue(name),
|
|
90
|
+
error: field.errorMessage.value ?? null,
|
|
91
|
+
validateOn: options.validateOn ?? "blur",
|
|
92
|
+
validating: validating.value,
|
|
93
|
+
defaultCountry: options.defaultCountry
|
|
94
|
+
}));
|
|
95
|
+
return {
|
|
96
|
+
phone,
|
|
97
|
+
country,
|
|
98
|
+
e164: computed(() => field.value.value ?? ""),
|
|
99
|
+
error: field.errorMessage,
|
|
100
|
+
validating,
|
|
101
|
+
meta: field.meta,
|
|
102
|
+
handleBlur: field.handleBlur,
|
|
103
|
+
validate: field.validate,
|
|
104
|
+
setErrors: field.setErrors,
|
|
105
|
+
resetField: field.resetField,
|
|
106
|
+
fieldProps
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
export { useTelField };
|
|
111
|
+
|
|
112
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/vee-validate/useTelField.ts"],"sourcesContent":["/**\n * VeeValidate adapter for `@alikhalilll/a-tel-input`.\n *\n * `useTelField()` owns the two v-models (`phone` + `country`) and the canonical\n * E.164 string used by VeeValidate / Zod / yup, and returns a single ready-to-bind\n * object so a consumer doesn't have to glue the pieces together.\n *\n * Quick start:\n *\n * ```ts\n * import { useTelField } from '@alikhalilll/a-tel-input/vee-validate';\n * import { toTypedSchema } from '@vee-validate/zod';\n * import { z } from 'zod';\n * import { zPhone } from '@alikhalilll/a-tel-input/zod';\n *\n * const { phone, country, error, handleBlur, fieldProps } = useTelField('phone', {\n * rules: toTypedSchema(zPhone()),\n * validateOn: 'blur',\n * });\n * ```\n *\n * ```vue\n * <ATelInput\n * v-model:phone=\"phone\"\n * v-model:country=\"country\"\n * v-bind=\"fieldProps\"\n * @blur=\"handleBlur\"\n * />\n * ```\n *\n * Server-side validation (e.g. \"does this phone already exist?\") plugs in via the\n * `rules` callback — VeeValidate already supports async rules:\n *\n * ```ts\n * const { phone, country, error, handleBlur, fieldProps, validating } = useTelField('phone', {\n * rules: async (value: string) => {\n * const sync = await zPhone().safeParseAsync(value);\n * if (!sync.success) return sync.error.issues[0]!.message;\n * const res = await $fetch('/api/phone/exists', { query: { phone: value } });\n * return res.exists ? 'This phone is already registered.' : true;\n * },\n * validateOn: 'blur',\n * });\n * ```\n *\n * The `validating` ref is `true` while VeeValidate's async pipeline is in flight —\n * bind it to ATelInput's `:validating` prop to surface a spinner inside the field.\n *\n * `vee-validate` is an **optional peer dependency** — install it yourself in your app.\n */\n\nimport { computed, ref, watch, type ComputedRef, type MaybeRefOrGetter } from 'vue';\nimport { toValue } from 'vue';\nimport { useField, type FieldOptions, type RuleExpression } from 'vee-validate';\nimport { usePhoneValidation } from '../composables/usePhoneValidation';\nimport type { ATelInputValidateOn } from '../composables/useTelInputValidation';\n\nexport interface UseTelFieldOptions {\n /**\n * VeeValidate rules — a function, schema, or string. Use when the field stands\n * alone (no `useForm` / no form-level `validationSchema`).\n *\n * **Important**: vee-validate **ignores field-level `rules` whenever the parent\n * `useForm` is configured with `validationSchema`**. If you need async / server-\n * side validation inside a form, chain it onto the form schema via\n * `z.refine(async)` instead — that's what `handleSubmit` actually awaits and what\n * drives this composable's `validating` ref (via `meta.pending`). See the README\n * section \"Server-side validation\" for the full pattern.\n */\n rules?: RuleExpression<string>;\n /**\n * Initial digits-only national number, e.g. `'1066105963'`. Defaults to `''`.\n */\n initialPhone?: string;\n /**\n * Initial dial-digit number, e.g. `20` for Egypt. Defaults to `null`.\n */\n initialCountry?: number | null;\n /**\n * Default country (ISO2 like `'EG'` or dial code like `'20'`). Forwarded as the\n * `defaultCountry` prop on `<ATelInput>` via `fieldProps`.\n */\n defaultCountry?: string;\n /**\n * When to surface validation in the UI. Defaults to `'blur'` (the typical form-library\n * UX). Forwarded as the `validateOn` prop on `<ATelInput>` via `fieldProps`.\n */\n validateOn?: ATelInputValidateOn;\n /**\n * Forwarded to `useField` — extra options passed verbatim to VeeValidate. Use to\n * configure `keepValueOnUnmount`, `syncVModel`, etc.\n */\n fieldOptions?: Omit<FieldOptions<string>, 'initialValue'>;\n}\n\nexport interface UseTelFieldReturn {\n /** `v-model:phone` source — digits-only national number. Bind to `<ATelInput>`. */\n phone: import('vue').Ref<string>;\n /** `v-model:country` source — dial-digit number (e.g., `20`). Bind to `<ATelInput>`. */\n country: import('vue').Ref<number | null>;\n /** The canonical E.164 string fed to VeeValidate's schema (read-only). */\n e164: ComputedRef<string>;\n /** Current validation error message, or `undefined` when valid. From `useField`. */\n error: import('vue').Ref<string | undefined>;\n /** `true` while VeeValidate is running an async rule (e.g. server-side check). */\n validating: ComputedRef<boolean>;\n /** Whether the field has been blurred / dirtied / submitted (from VeeValidate `meta`). */\n meta: ReturnType<typeof useField<string>>['meta'];\n /** Forward this to `<ATelInput @blur=\"handleBlur\">` so VeeValidate's blur trigger fires. */\n handleBlur: ReturnType<typeof useField<string>>['handleBlur'];\n /** Imperatively trigger validation (e.g., after a programmatic value change). */\n validate: ReturnType<typeof useField<string>>['validate'];\n /** Imperatively set the error message — useful for server errors not raised by `rules`. */\n setErrors: ReturnType<typeof useField<string>>['setErrors'];\n /** Reset the field to its initial state. */\n resetField: ReturnType<typeof useField<string>>['resetField'];\n /**\n * Ready-to-bind prop bag for `<ATelInput v-bind=\"fieldProps\">`. Carries `name`,\n * `error`, `validateOn`, `validating`, and `defaultCountry`.\n */\n fieldProps: ComputedRef<{\n name: string;\n error: string | null;\n validateOn: ATelInputValidateOn;\n validating: boolean;\n defaultCountry?: string;\n }>;\n}\n\n/**\n * Register a phone field with VeeValidate. See file header for usage examples.\n *\n * @param name The field name (used by VeeValidate, also forwarded to the inner\n * `<input name=\"\">` for native form submission).\n * @param options See {@link UseTelFieldOptions}.\n */\nexport function useTelField(\n name: MaybeRefOrGetter<string>,\n options: UseTelFieldOptions = {}\n): UseTelFieldReturn {\n const phone = ref<string>(options.initialPhone ?? '');\n const country = ref<number | null>(options.initialCountry ?? null);\n\n const v = usePhoneValidation();\n void v.getCountries();\n\n // Compose E.164 from the two v-models — this is the canonical value VeeValidate\n // tracks. NANP (`+1`) resolves to `'US'` for validation; libphonenumber-js applies\n // the same rule set to every NANP country so this is correct.\n function composeE164(): string {\n if (!phone.value) return '';\n const dial = country.value;\n if (dial == null) return '';\n const matches = v.getCountriesByDial(String(dial));\n const iso2 = matches[0]?.value;\n if (!iso2) return '';\n const res = v.validate({ country: { iso2 }, phone: phone.value });\n return res.full_phone ?? '';\n }\n\n const initialValue = composeE164();\n\n const field = useField<string>(name, options.rules, {\n initialValue,\n // Don't run rules on every keystroke — let validateOn drive when validation fires.\n validateOnValueUpdate: false,\n ...options.fieldOptions,\n });\n\n // Keep VeeValidate's value in sync with the two v-models.\n watch(\n [phone, country],\n () => {\n field.value.value = composeE164();\n },\n { flush: 'post' }\n );\n\n const validating = computed(() => !!field.meta.pending);\n\n const fieldProps = computed(() => ({\n name: toValue(name),\n error: (field.errorMessage.value ?? null) as string | null,\n validateOn: options.validateOn ?? ('blur' as ATelInputValidateOn),\n validating: validating.value,\n defaultCountry: options.defaultCountry,\n }));\n\n return {\n phone,\n country,\n e164: computed(() => field.value.value ?? ''),\n error: field.errorMessage,\n validating,\n meta: field.meta,\n handleBlur: field.handleBlur,\n validate: field.validate,\n setErrors: field.setErrors,\n resetField: field.resetField,\n fieldProps,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwIA,SAAgB,YACd,MACA,UAA8B,CAAC,GACZ;CACnB,MAAM,QAAQ,IAAY,QAAQ,gBAAgB,EAAE;CACpD,MAAM,UAAU,IAAmB,QAAQ,kBAAkB,IAAI;CAEjE,MAAM,IAAI,mBAAmB;CAC7B,EAAO,aAAa;CAKpB,SAAS,cAAsB;EAC7B,IAAI,CAAC,MAAM,OAAO,OAAO;EACzB,MAAM,OAAO,QAAQ;EACrB,IAAI,QAAQ,MAAM,OAAO;EAEzB,MAAM,OADU,EAAE,mBAAmB,OAAO,IAAI,CAC7B,EAAE,IAAI;EACzB,IAAI,CAAC,MAAM,OAAO;EAElB,OADY,EAAE,SAAS;GAAE,SAAS,EAAE,KAAK;GAAG,OAAO,MAAM;EAAM,CACtD,EAAE,cAAc;CAC3B;CAEA,MAAM,eAAe,YAAY;CAEjC,MAAM,QAAQ,SAAiB,MAAM,QAAQ,OAAO;EAClD;EAEA,uBAAuB;EACvB,GAAG,QAAQ;CACb,CAAC;CAGD,MACE,CAAC,OAAO,OAAO,SACT;EACJ,MAAM,MAAM,QAAQ,YAAY;CAClC,GACA,EAAE,OAAO,OAAO,CAClB;CAEA,MAAM,aAAa,eAAe,CAAC,CAAC,MAAM,KAAK,OAAO;CAEtD,MAAM,aAAa,gBAAgB;EACjC,MAAM,QAAQ,IAAI;EAClB,OAAQ,MAAM,aAAa,SAAS;EACpC,YAAY,QAAQ,cAAe;EACnC,YAAY,WAAW;EACvB,gBAAgB,QAAQ;CAC1B,EAAE;CAEF,OAAO;EACL;EACA;EACA,MAAM,eAAe,MAAM,MAAM,SAAS,EAAE;EAC5C,OAAO,MAAM;EACb;EACA,MAAM,MAAM;EACZ,YAAY,MAAM;EAClB,UAAU,MAAM;EAChB,WAAW,MAAM;EACjB,YAAY,MAAM;EAClB;CACF;AACF"}
|