@alikhalilll/a-tel-input 1.0.2 → 1.1.1
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/.media/README.md +3 -0
- package/.media/hero.png +0 -0
- package/README.md +597 -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 +471 -695
- 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 +454 -658
- package/dist/index.js.map +1 -1
- package/dist/styles.css +20 -5
- 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 +34 -3
- package/src/components/ACountrySelect.vue +17 -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}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.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] {
|
|
@@ -112,7 +112,9 @@ to {
|
|
|
112
112
|
}
|
|
113
113
|
.a-country-select__search {
|
|
114
114
|
border-bottom: 1px solid hsl(var(--ak-ui-border) / 0.7);
|
|
115
|
-
padding
|
|
115
|
+
/* Drop bottom padding — the list owns the gap below the search border so the
|
|
116
|
+
sticky group header can overlap it and sit flush against the search bar. */
|
|
117
|
+
padding: 0.375rem 0.375rem 0;
|
|
116
118
|
}
|
|
117
119
|
.a-country-select__search-box {
|
|
118
120
|
position: relative;
|
|
@@ -179,6 +181,10 @@ to {
|
|
|
179
181
|
.a-country-select__list {
|
|
180
182
|
flex: 1;
|
|
181
183
|
overflow-y: auto;
|
|
184
|
+
/* Top padding lives inside the scroll container so the first sticky group header
|
|
185
|
+
can overlap it (via negative `top`) and sit flush against the search border
|
|
186
|
+
with zero visible gap. */
|
|
187
|
+
padding-top: 0.375rem;
|
|
182
188
|
/* Themed scrollbar — Firefox + WebKit/Blink. Resolves the browser-default
|
|
183
189
|
light-grey scrollbar that didn't match the popover surface in dark mode. */
|
|
184
190
|
scrollbar-width: thin;
|
|
@@ -207,16 +213,24 @@ to {
|
|
|
207
213
|
}
|
|
208
214
|
.a-country-select__group-header {
|
|
209
215
|
position: sticky;
|
|
210
|
-
top
|
|
216
|
+
/* Negative top equal to the list's `padding-top` makes the sticky header
|
|
217
|
+
overlap that padding band so when the user scrolls it sits flush against
|
|
218
|
+
the search bar's bottom border — no visible gap. */
|
|
219
|
+
top: -0.375rem;
|
|
211
220
|
z-index: 10;
|
|
212
221
|
background: hsl(var(--ak-ui-popover));
|
|
213
222
|
color: hsl(var(--ak-ui-muted-foreground));
|
|
214
|
-
padding
|
|
223
|
+
/* Extra top padding compensates for the negative `top` offset so the visible
|
|
224
|
+
label keeps its usual breathing room. */
|
|
225
|
+
padding: 0.5rem 0.75rem 0.375rem;
|
|
215
226
|
font-size: 10px;
|
|
216
227
|
font-weight: 500;
|
|
217
228
|
letter-spacing: 0.05em;
|
|
218
229
|
text-transform: uppercase;
|
|
219
230
|
margin: 0;
|
|
231
|
+
/* Hairline under the header that only shows once it's stuck — helps it read
|
|
232
|
+
as a distinct band from the search border above. */
|
|
233
|
+
box-shadow: 0 1px 0 0 hsl(var(--ak-ui-border) / 0.5);
|
|
220
234
|
}
|
|
221
235
|
.a-country-select__group-list {
|
|
222
236
|
list-style: none;
|
|
@@ -411,7 +425,8 @@ to {
|
|
|
411
425
|
.a-tel-input__input[data-has-dial][data-v-8305dc81] {
|
|
412
426
|
padding-inline-start: 0.25rem;
|
|
413
427
|
}
|
|
414
|
-
.a-tel-input__detecting[data-v-8305dc81]
|
|
428
|
+
.a-tel-input__detecting[data-v-8305dc81],
|
|
429
|
+
.a-tel-input__validating[data-v-8305dc81] {
|
|
415
430
|
display: inline-flex;
|
|
416
431
|
height: 100%;
|
|
417
432
|
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"}
|