@umbra.ui/core 0.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/dist/components/controls/Dropdown/types.d.ts +5 -0
- package/dist/components/controls/Dropdown/types.d.ts.map +1 -0
- package/dist/components/controls/Dropdown/types.js +1 -0
- package/dist/components/controls/SegmentedControl/types.d.ts +6 -0
- package/dist/components/controls/SegmentedControl/types.d.ts.map +1 -0
- package/dist/components/controls/SegmentedControl/types.js +1 -0
- package/dist/components/dialogs/Alert/types.d.ts +7 -0
- package/dist/components/dialogs/Alert/types.d.ts.map +1 -0
- package/dist/components/dialogs/Alert/types.js +1 -0
- package/dist/components/dialogs/Toast/types.d.ts +34 -0
- package/dist/components/dialogs/Toast/types.d.ts.map +1 -0
- package/dist/components/dialogs/Toast/types.js +10 -0
- package/dist/components/dialogs/Toast/useToast.d.ts +36 -0
- package/dist/components/dialogs/Toast/useToast.d.ts.map +1 -0
- package/dist/components/dialogs/Toast/useToast.js +90 -0
- package/dist/components/indicators/Tooltip/tooltip.d.ts +3 -0
- package/dist/components/indicators/Tooltip/tooltip.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/tooltip.js +33 -0
- package/dist/components/indicators/Tooltip/types.d.ts +14 -0
- package/dist/components/indicators/Tooltip/types.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/types.js +1 -0
- package/dist/components/indicators/Tooltip/useTooltip.d.ts +18 -0
- package/dist/components/indicators/Tooltip/useTooltip.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/useTooltip.js +57 -0
- package/dist/components/inputs/Tags/tag-bar-styles.d.ts +14 -0
- package/dist/components/inputs/Tags/tag-bar-styles.d.ts.map +1 -0
- package/dist/components/inputs/Tags/tag-bar-styles.js +313 -0
- package/dist/components/inputs/Tags/types.d.ts +93 -0
- package/dist/components/inputs/Tags/types.d.ts.map +1 -0
- package/dist/components/inputs/Tags/types.js +216 -0
- package/dist/components/inputs/search/types.d.ts +9 -0
- package/dist/components/inputs/search/types.d.ts.map +1 -0
- package/dist/components/inputs/search/types.js +1 -0
- package/dist/components/navigation/adaptive/types.d.ts +16 -0
- package/dist/components/navigation/adaptive/types.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/types.js +1 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.d.ts +27 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.js +40 -0
- package/dist/components/navigation/adaptive/useBreakpoints.d.ts +6 -0
- package/dist/components/navigation/adaptive/useBreakpoints.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useBreakpoints.js +37 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.d.ts +93 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.js +145 -0
- package/dist/components/navigation/adaptive/useViewAnimation.d.ts +31 -0
- package/dist/components/navigation/adaptive/useViewAnimation.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useViewAnimation.js +591 -0
- package/dist/components/navigation/adaptive/useViewResize.d.ts +52 -0
- package/dist/components/navigation/adaptive/useViewResize.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useViewResize.js +146 -0
- package/dist/components/navigation/navstack/useNavigationStack.d.ts +25 -0
- package/dist/components/navigation/navstack/useNavigationStack.d.ts.map +1 -0
- package/dist/components/navigation/navstack/useNavigationStack.js +133 -0
- package/dist/components/navigation/slideover/useSlideoverController.d.ts +20 -0
- package/dist/components/navigation/slideover/useSlideoverController.d.ts.map +1 -0
- package/dist/components/navigation/slideover/useSlideoverController.js +267 -0
- package/dist/components/navigation/splitview/useSplitViewController.d.ts +20 -0
- package/dist/components/navigation/splitview/useSplitViewController.d.ts.map +1 -0
- package/dist/components/navigation/splitview/useSplitViewController.js +325 -0
- package/dist/components/navigation/tabcontroller/types.d.ts +21 -0
- package/dist/components/navigation/tabcontroller/types.d.ts.map +1 -0
- package/dist/components/navigation/tabcontroller/types.js +1 -0
- package/dist/components/navigation/tabcontroller/useTabController.d.ts +5 -0
- package/dist/components/navigation/tabcontroller/useTabController.d.ts.map +1 -0
- package/dist/components/navigation/tabcontroller/useTabController.js +10 -0
- package/dist/components/navigation/types.d.ts +8 -0
- package/dist/components/navigation/types.d.ts.map +1 -0
- package/dist/components/navigation/types.js +1 -0
- package/dist/components/pickers/CollectionPicker/types.d.ts +11 -0
- package/dist/components/pickers/CollectionPicker/types.d.ts.map +1 -0
- package/dist/components/pickers/CollectionPicker/types.js +1 -0
- package/dist/components/pickers/ColorPicker/colors.d.ts +13 -0
- package/dist/components/pickers/ColorPicker/colors.d.ts.map +1 -0
- package/dist/components/pickers/ColorPicker/colors.js +266 -0
- package/dist/components/pickers/FilePicker/types.d.ts +10 -0
- package/dist/components/pickers/FilePicker/types.d.ts.map +1 -0
- package/dist/components/pickers/FilePicker/types.js +1 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +196 -0
- package/dist/theme.d.ts +73 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +279 -0
- package/dist/themes/blank.d.ts +7 -0
- package/dist/themes/blank.d.ts.map +1 -0
- package/dist/themes/blank.js +543 -0
- package/dist/themes/crimson-dark.d.ts +4 -0
- package/dist/themes/crimson-dark.d.ts.map +1 -0
- package/dist/themes/crimson-dark.js +552 -0
- package/dist/themes/cyan-light.d.ts +4 -0
- package/dist/themes/cyan-light.d.ts.map +1 -0
- package/dist/themes/cyan-light.js +552 -0
- package/dist/themes/dark.d.ts +4 -0
- package/dist/themes/dark.d.ts.map +1 -0
- package/dist/themes/dark.js +551 -0
- package/dist/themes/gold-dark.d.ts +4 -0
- package/dist/themes/gold-dark.d.ts.map +1 -0
- package/dist/themes/gold-dark.js +552 -0
- package/dist/themes/grass-dark.d.ts +4 -0
- package/dist/themes/grass-dark.d.ts.map +1 -0
- package/dist/themes/grass-dark.js +552 -0
- package/dist/themes/indigo.d.ts +4 -0
- package/dist/themes/indigo.d.ts.map +1 -0
- package/dist/themes/indigo.js +552 -0
- package/dist/themes/light.d.ts +4 -0
- package/dist/themes/light.d.ts.map +1 -0
- package/dist/themes/light.js +551 -0
- package/dist/themes/orange-dark.d.ts +4 -0
- package/dist/themes/orange-dark.d.ts.map +1 -0
- package/dist/themes/orange-dark.js +551 -0
- package/dist/themes/orange-light.d.ts +4 -0
- package/dist/themes/orange-light.d.ts.map +1 -0
- package/dist/themes/orange-light.js +551 -0
- package/package.json +62 -0
- package/src/components/controls/Button/Button.vue +417 -0
- package/src/components/controls/Button/README.md +348 -0
- package/src/components/controls/Button/theme.css +200 -0
- package/src/components/controls/Checkbox/Checkbox.vue +164 -0
- package/src/components/controls/Checkbox/README.md +441 -0
- package/src/components/controls/Checkbox/theme.css +36 -0
- package/src/components/controls/Dropdown/Dropdown.vue +476 -0
- package/src/components/controls/Dropdown/README.md +370 -0
- package/src/components/controls/Dropdown/theme.css +50 -0
- package/src/components/controls/Dropdown/types.ts +6 -0
- package/src/components/controls/IconButton/IconButton.vue +267 -0
- package/src/components/controls/IconButton/README.md +502 -0
- package/src/components/controls/IconButton/theme.css +89 -0
- package/src/components/controls/Radio/README.md +591 -0
- package/src/components/controls/Radio/Radio.vue +89 -0
- package/src/components/controls/Radio/theme.css +14 -0
- package/src/components/controls/RangeSlider/README.md +608 -0
- package/src/components/controls/RangeSlider/RangeSlider.vue +535 -0
- package/src/components/controls/RangeSlider/theme.css +80 -0
- package/src/components/controls/SegmentedControl/README.md +587 -0
- package/src/components/controls/SegmentedControl/SegmentedControl.vue +284 -0
- package/src/components/controls/SegmentedControl/theme.css +60 -0
- package/src/components/controls/SegmentedControl/types.ts +5 -0
- package/src/components/controls/Slider/README.md +627 -0
- package/src/components/controls/Slider/Slider.vue +260 -0
- package/src/components/controls/Slider/theme.css +74 -0
- package/src/components/controls/Stepper/README.md +601 -0
- package/src/components/controls/Stepper/Stepper.vue +103 -0
- package/src/components/controls/Stepper/theme.css +53 -0
- package/src/components/controls/Switch/README.md +667 -0
- package/src/components/controls/Switch/Switch.vue +127 -0
- package/src/components/controls/Switch/theme.css +42 -0
- package/src/components/dialogs/Alert/Alert.vue +218 -0
- package/src/components/dialogs/Alert/README.md +450 -0
- package/src/components/dialogs/Alert/theme.css +44 -0
- package/src/components/dialogs/Alert/types.ts +11 -0
- package/src/components/dialogs/Toast/README.md +522 -0
- package/src/components/dialogs/Toast/Toast.vue +296 -0
- package/src/components/dialogs/Toast/ToastContainer.vue +330 -0
- package/src/components/dialogs/Toast/theme.css +44 -0
- package/src/components/dialogs/Toast/types.ts +46 -0
- package/src/components/dialogs/Toast/useToast.ts +127 -0
- package/src/components/indicators/ProgressBar/ProgressBar.vue +98 -0
- package/src/components/indicators/ProgressBar/README.md +744 -0
- package/src/components/indicators/ProgressBar/theme.css +36 -0
- package/src/components/indicators/Tooltip/README.md +723 -0
- package/src/components/indicators/Tooltip/TooltipProvider.vue +142 -0
- package/src/components/indicators/Tooltip/theme.css +18 -0
- package/src/components/indicators/Tooltip/tooltip.ts +48 -0
- package/src/components/indicators/Tooltip/types.ts +15 -0
- package/src/components/indicators/Tooltip/useTooltip.ts +71 -0
- package/src/components/inputs/AutogrowTextView/AutogrowTextView.vue +110 -0
- package/src/components/inputs/AutogrowTextView/README.md +643 -0
- package/src/components/inputs/AutogrowTextView/theme.css +28 -0
- package/src/components/inputs/InputCard/InputCard.vue +600 -0
- package/src/components/inputs/InputCard/README.md +636 -0
- package/src/components/inputs/InputEmail/InputEmail.vue +698 -0
- package/src/components/inputs/InputEmail/README.md +764 -0
- package/src/components/inputs/InputNumber/InputNumber.vue +300 -0
- package/src/components/inputs/InputNumber/README.md +749 -0
- package/src/components/inputs/InputPhone/InputPhone.vue +645 -0
- package/src/components/inputs/InputPhone/README.md +636 -0
- package/src/components/inputs/InputSecure/InputSecure.vue +646 -0
- package/src/components/inputs/InputSecure/README.md +771 -0
- package/src/components/inputs/InputText/InputText.vue +225 -0
- package/src/components/inputs/InputText/README.md +844 -0
- package/src/components/inputs/OTP/OTP.vue +349 -0
- package/src/components/inputs/OTP/README.md +736 -0
- package/src/components/inputs/OTP/theme.css +50 -0
- package/src/components/inputs/StringCapture/README.md +718 -0
- package/src/components/inputs/StringCapture/StringCapture.vue +315 -0
- package/src/components/inputs/StringCapture/theme.css +86 -0
- package/src/components/inputs/Tags/README.md +897 -0
- package/src/components/inputs/Tags/TagBar.vue +793 -0
- package/src/components/inputs/Tags/TagCreation.vue +219 -0
- package/src/components/inputs/Tags/TagPicker.vue +380 -0
- package/src/components/inputs/Tags/tag-bar-styles.ts +354 -0
- package/src/components/inputs/Tags/theme.css +121 -0
- package/src/components/inputs/Tags/types.ts +346 -0
- package/src/components/inputs/search/README.md +759 -0
- package/src/components/inputs/search/SearchBar.vue +394 -0
- package/src/components/inputs/search/SearchResults.vue +310 -0
- package/src/components/inputs/search/theme.css +187 -0
- package/src/components/inputs/search/types.ts +8 -0
- package/src/components/inputs/theme.css +102 -0
- package/src/components/menus/ActionMenu/ActionMenu.vue +383 -0
- package/src/components/menus/ActionMenu/README.md +825 -0
- package/src/components/menus/ActionMenu/theme.css +93 -0
- package/src/components/models/Popover/Popover.vue +551 -0
- package/src/components/models/Popover/README.md +885 -0
- package/src/components/models/Popover/theme.css +52 -0
- package/src/components/models/Sheet/README.md +1159 -0
- package/src/components/models/Sheet/Sheet.vue +465 -0
- package/src/components/models/Sheet/theme.css +72 -0
- package/src/components/models/Sidebar/README.md +1228 -0
- package/src/components/models/Sidebar/Sidebar.vue +480 -0
- package/src/components/models/Sidebar/theme.css +90 -0
- package/src/components/navigation/adaptive/AdaptiveLayout.vue +779 -0
- package/src/components/navigation/adaptive/AdaptiveLayoutBreadcrumbs.vue +192 -0
- package/src/components/navigation/adaptive/AdaptiveLayoutMenuButton.vue +149 -0
- package/src/components/navigation/adaptive/README.md +768 -0
- package/src/components/navigation/adaptive/types.ts +19 -0
- package/src/components/navigation/adaptive/useAdaptiveLayout.ts +89 -0
- package/src/components/navigation/adaptive/useBreakpoints.ts +41 -0
- package/src/components/navigation/adaptive/useContainerMonitor.ts +214 -0
- package/src/components/navigation/adaptive/useViewAnimation.ts +721 -0
- package/src/components/navigation/adaptive/useViewResize.ts +211 -0
- package/src/components/navigation/navstack/NavigationStack.vue +180 -0
- package/src/components/navigation/navstack/README.md +994 -0
- package/src/components/navigation/navstack/useNavigationStack.ts +164 -0
- package/src/components/navigation/slideover/README.md +1275 -0
- package/src/components/navigation/slideover/SlideoverController.vue +287 -0
- package/src/components/navigation/slideover/useSlideoverController.ts +320 -0
- package/src/components/navigation/splitview/README.md +1115 -0
- package/src/components/navigation/splitview/SplitViewController.vue +176 -0
- package/src/components/navigation/splitview/useSplitViewController.ts +388 -0
- package/src/components/navigation/tabcontroller/README.md +919 -0
- package/src/components/navigation/tabcontroller/TabController.vue +307 -0
- package/src/components/navigation/tabcontroller/TabItem.vue +57 -0
- package/src/components/navigation/tabcontroller/types.ts +24 -0
- package/src/components/navigation/tabcontroller/useTabController.ts +18 -0
- package/src/components/navigation/theme.css +91 -0
- package/src/components/navigation/types.ts +7 -0
- package/src/components/pickers/CollectionPicker/CollectionPicker.vue +398 -0
- package/src/components/pickers/CollectionPicker/README.md +1115 -0
- package/src/components/pickers/CollectionPicker/theme.css +14 -0
- package/src/components/pickers/CollectionPicker/types.ts +11 -0
- package/src/components/pickers/ColorPicker/ColorPicker.vue +376 -0
- package/src/components/pickers/ColorPicker/README.md +1439 -0
- package/src/components/pickers/ColorPicker/colors.ts +299 -0
- package/src/components/pickers/ColorPicker/theme.css +32 -0
- package/src/components/pickers/DatePicker/DatePicker.vue +660 -0
- package/src/components/pickers/DatePicker/README.md +1195 -0
- package/src/components/pickers/DatePicker/theme.css +22 -0
- package/src/components/pickers/FilePicker/FilePicker.vue +534 -0
- package/src/components/pickers/FilePicker/README.md +1542 -0
- package/src/components/pickers/FilePicker/theme.css +48 -0
- package/src/components/pickers/FilePicker/types.ts +10 -0
- package/src/components/pickers/IconPicker/IconPicker.vue +327 -0
- package/src/components/pickers/IconPicker/README.md +1161 -0
- package/src/components/pickers/IconPicker/theme.css +28 -0
- package/src/components/pickers/theme.css +82 -0
- package/src/components/views/MarkdownViewer/MarkdownViewer.vue +442 -0
- package/src/components/views/MarkdownViewer/README.md +833 -0
- package/src/components/views/MarkdownViewer/theme.css +130 -0
- package/src/index.ts +263 -0
- package/src/theme.ts +378 -0
- package/src/themes/crimson-dark.ts +556 -0
- package/src/themes/cyan-light.ts +556 -0
- package/src/themes/dark.ts +557 -0
- package/src/themes/gold-dark.ts +556 -0
- package/src/themes/grass-dark.ts +556 -0
- package/src/themes/indigo.ts +556 -0
- package/src/themes/light.ts +557 -0
- package/src/themes/orange-dark.ts +557 -0
- package/src/themes/orange-light.ts +557 -0
- package/src/vue.d.ts +45 -0
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
# InputPhone
|
|
2
|
+
|
|
3
|
+
A specialized phone number input component built with Vue 3 Composition API and TypeScript. The InputPhone component provides automatic phone number formatting, country detection, validation, and visual feedback with smooth animations and accessibility features.
|
|
4
|
+
|
|
5
|
+
## Installation/Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { InputPhone } from "@umbra-ui/core";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**Dependencies:**
|
|
12
|
+
|
|
13
|
+
- Vue 3.x
|
|
14
|
+
- @umbra-ui/icons (for phone, warning, and check icons)
|
|
15
|
+
|
|
16
|
+
## Basic Usage
|
|
17
|
+
|
|
18
|
+
```vue
|
|
19
|
+
<script setup lang="ts">
|
|
20
|
+
import { ref } from "vue";
|
|
21
|
+
import { InputPhone } from "@umbra-ui/core";
|
|
22
|
+
|
|
23
|
+
const phoneNumber = ref("");
|
|
24
|
+
|
|
25
|
+
const handlePhoneUpdate = (value: string) => {
|
|
26
|
+
console.log("Phone:", value);
|
|
27
|
+
phoneNumber.value = value;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const handleFormattedUpdate = (formatted: string) => {
|
|
31
|
+
console.log("Formatted:", formatted);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const handleValidUpdate = (isValid: boolean) => {
|
|
35
|
+
console.log("Valid:", isValid);
|
|
36
|
+
};
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<template>
|
|
40
|
+
<div>
|
|
41
|
+
<InputPhone
|
|
42
|
+
v-model:value="phoneNumber"
|
|
43
|
+
@update:formatted="handleFormattedUpdate"
|
|
44
|
+
@update:valid="handleValidUpdate"
|
|
45
|
+
placeholder="Enter phone number"
|
|
46
|
+
default-country="US"
|
|
47
|
+
:allow-international="true"
|
|
48
|
+
:show-country-code="true"
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
</template>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Props
|
|
55
|
+
|
|
56
|
+
| Prop Name | Type | Required | Default | Description |
|
|
57
|
+
| -------------------- | ------------------------------------------------------------- | -------- | ---------------------- | -------------------------------------------- |
|
|
58
|
+
| `value` | `string` | No | `""` | The phone number value |
|
|
59
|
+
| `placeholder` | `string` | No | `"Enter phone number"` | Placeholder text displayed when empty |
|
|
60
|
+
| `defaultCountry` | `string` | No | `"US"` | ISO country code for default formatting |
|
|
61
|
+
| `allowInternational` | `boolean` | No | `true` | Whether to allow international phone numbers |
|
|
62
|
+
| `showCountryCode` | `boolean` | No | `true` | Whether to show country code when detected |
|
|
63
|
+
| `state` | `"normal" \| "active" \| "disabled" \| "readonly" \| "error"` | No | `"normal"` | Current state of the input field |
|
|
64
|
+
|
|
65
|
+
## Events
|
|
66
|
+
|
|
67
|
+
| Event Name | Payload Type | Description |
|
|
68
|
+
| ------------------ | ------------ | ----------------------------------------------- |
|
|
69
|
+
| `update:value` | `string` | Emitted when the phone number value changes |
|
|
70
|
+
| `update:formatted` | `string` | Emitted when the formatted phone number changes |
|
|
71
|
+
| `update:valid` | `boolean` | Emitted when the validation state changes |
|
|
72
|
+
|
|
73
|
+
## Slots
|
|
74
|
+
|
|
75
|
+
This component does not provide any slots.
|
|
76
|
+
|
|
77
|
+
## Exposed Methods/Refs
|
|
78
|
+
|
|
79
|
+
This component does not expose any methods or refs.
|
|
80
|
+
|
|
81
|
+
## CSS Customization
|
|
82
|
+
|
|
83
|
+
The InputPhone component uses CSS custom properties for theming and customization:
|
|
84
|
+
|
|
85
|
+
### Input Container Variables
|
|
86
|
+
|
|
87
|
+
```css
|
|
88
|
+
--input-border: 1px solid var(--input-border-color);
|
|
89
|
+
--input-border-radius: 0.588rem;
|
|
90
|
+
--input-focus-border: var(--input-focus-color);
|
|
91
|
+
--input-background-normal: var(--input-bg-normal);
|
|
92
|
+
--input-background-filled: var(--input-bg-filled);
|
|
93
|
+
--input-border-filled: var(--input-border-filled-color);
|
|
94
|
+
--input-text-empty: var(--input-text-empty-color);
|
|
95
|
+
--input-text-filled: var(--input-text-filled-color);
|
|
96
|
+
--input-placeholder: var(--input-placeholder-color);
|
|
97
|
+
--input-placeholder-filled: var(--input-placeholder-filled-color);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### State-Specific Variables
|
|
101
|
+
|
|
102
|
+
```css
|
|
103
|
+
/* Disabled State */
|
|
104
|
+
--input-disabled-bg: var(--input-disabled-background);
|
|
105
|
+
--input-disabled-text: var(--input-disabled-text-color);
|
|
106
|
+
--input-disabled-border: var(--input-disabled-border-color);
|
|
107
|
+
--input-disabled-placeholder: var(--input-disabled-placeholder-color);
|
|
108
|
+
|
|
109
|
+
/* Readonly State */
|
|
110
|
+
--input-readonly-bg: var(--input-readonly-background);
|
|
111
|
+
--input-readonly-text: var(--input-readonly-text-color);
|
|
112
|
+
--input-readonly-border: var(--input-readonly-border-color);
|
|
113
|
+
--input-readonly-placeholder: var(--input-readonly-placeholder-color);
|
|
114
|
+
|
|
115
|
+
/* Error State */
|
|
116
|
+
--input-error-bg: var(--input-error-background);
|
|
117
|
+
--input-error-text: var(--input-error-text-color);
|
|
118
|
+
--input-error-border: var(--input-error-border-color);
|
|
119
|
+
--input-text-error: var(--input-error-text-color);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Key Features
|
|
123
|
+
|
|
124
|
+
### Automatic Formatting
|
|
125
|
+
|
|
126
|
+
- **Country Detection**: Automatically detects country from phone number patterns
|
|
127
|
+
- **Real-time Formatting**: Formats phone numbers as the user types
|
|
128
|
+
- **Multiple Formats**: Supports US, UK, and international phone number formats
|
|
129
|
+
- **Smart Cursor Positioning**: Maintains proper cursor position during formatting
|
|
130
|
+
|
|
131
|
+
### Validation
|
|
132
|
+
|
|
133
|
+
- **Real-time Validation**: Validates phone numbers based on country-specific rules
|
|
134
|
+
- **Visual Feedback**: Shows validation state with icons and error messages
|
|
135
|
+
- **Digit Limits**: Enforces country-specific digit limits (US: 10/11, UK: 11/12, International: 7-15)
|
|
136
|
+
- **E.164 Compliance**: Follows international E.164 standard for phone numbers
|
|
137
|
+
|
|
138
|
+
### User Experience
|
|
139
|
+
|
|
140
|
+
- **Input Restrictions**: Only allows digits and formatting characters
|
|
141
|
+
- **Paste Support**: Handles pasted phone numbers with proper formatting
|
|
142
|
+
- **Keyboard Navigation**: Supports standard keyboard navigation and editing
|
|
143
|
+
- **Responsive Design**: Adapts to different screen sizes with proper font scaling
|
|
144
|
+
|
|
145
|
+
### Supported Countries
|
|
146
|
+
|
|
147
|
+
- **US**: `(555) 123-4567` or `+1 (555) 123-4567`
|
|
148
|
+
- **UK**: `20 1234 5678` or `+44 20 1234 5678`
|
|
149
|
+
- **International**: Generic formatting with country codes
|
|
150
|
+
|
|
151
|
+
## Examples
|
|
152
|
+
|
|
153
|
+
### Basic Phone Input
|
|
154
|
+
|
|
155
|
+
```vue
|
|
156
|
+
<script setup lang="ts">
|
|
157
|
+
import { ref } from "vue";
|
|
158
|
+
import { InputPhone } from "@umbra-ui/core";
|
|
159
|
+
|
|
160
|
+
const phone = ref("");
|
|
161
|
+
</script>
|
|
162
|
+
|
|
163
|
+
<template>
|
|
164
|
+
<div class="phone-form">
|
|
165
|
+
<h3>Contact Information</h3>
|
|
166
|
+
|
|
167
|
+
<div class="form-group">
|
|
168
|
+
<label>Phone Number</label>
|
|
169
|
+
<InputPhone
|
|
170
|
+
v-model:value="phone"
|
|
171
|
+
placeholder="Enter your phone number"
|
|
172
|
+
default-country="US"
|
|
173
|
+
/>
|
|
174
|
+
</div>
|
|
175
|
+
|
|
176
|
+
<div class="phone-display">
|
|
177
|
+
<p>Entered: {{ phone }}</p>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</template>
|
|
181
|
+
|
|
182
|
+
<style module>
|
|
183
|
+
.phone-form {
|
|
184
|
+
max-width: 400px;
|
|
185
|
+
padding: 1.5rem;
|
|
186
|
+
border: 1px solid #e0e0e0;
|
|
187
|
+
border-radius: 0.5rem;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.form-group {
|
|
191
|
+
margin-bottom: 1rem;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.form-group label {
|
|
195
|
+
display: block;
|
|
196
|
+
margin-bottom: 0.5rem;
|
|
197
|
+
font-weight: 500;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.phone-display {
|
|
201
|
+
margin-top: 1rem;
|
|
202
|
+
padding: 1rem;
|
|
203
|
+
background-color: #f5f5f5;
|
|
204
|
+
border-radius: 0.25rem;
|
|
205
|
+
}
|
|
206
|
+
</style>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### International Phone Numbers
|
|
210
|
+
|
|
211
|
+
```vue
|
|
212
|
+
<script setup lang="ts">
|
|
213
|
+
import { ref } from "vue";
|
|
214
|
+
import { InputPhone } from "@umbra-ui/core";
|
|
215
|
+
|
|
216
|
+
const internationalPhone = ref("");
|
|
217
|
+
const isValid = ref(false);
|
|
218
|
+
const formatted = ref("");
|
|
219
|
+
|
|
220
|
+
const handleValidUpdate = (valid: boolean) => {
|
|
221
|
+
isValid.value = valid;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const handleFormattedUpdate = (formattedValue: string) => {
|
|
225
|
+
formatted.value = formattedValue;
|
|
226
|
+
};
|
|
227
|
+
</script>
|
|
228
|
+
|
|
229
|
+
<template>
|
|
230
|
+
<div class="international-example">
|
|
231
|
+
<h3>International Phone Numbers</h3>
|
|
232
|
+
|
|
233
|
+
<div class="form-group">
|
|
234
|
+
<label>Phone Number (Any Country)</label>
|
|
235
|
+
<InputPhone
|
|
236
|
+
v-model:value="internationalPhone"
|
|
237
|
+
@update:valid="handleValidUpdate"
|
|
238
|
+
@update:formatted="handleFormattedUpdate"
|
|
239
|
+
placeholder="Enter international phone number"
|
|
240
|
+
default-country="US"
|
|
241
|
+
:allow-international="true"
|
|
242
|
+
:show-country-code="true"
|
|
243
|
+
/>
|
|
244
|
+
</div>
|
|
245
|
+
|
|
246
|
+
<div class="validation-status">
|
|
247
|
+
<div class="status-item">
|
|
248
|
+
<strong>Valid:</strong>
|
|
249
|
+
<span :class="{ valid: isValid, invalid: !isValid }">
|
|
250
|
+
{{ isValid ? "Yes" : "No" }}
|
|
251
|
+
</span>
|
|
252
|
+
</div>
|
|
253
|
+
<div class="status-item"><strong>Formatted:</strong> {{ formatted }}</div>
|
|
254
|
+
</div>
|
|
255
|
+
</div>
|
|
256
|
+
</template>
|
|
257
|
+
|
|
258
|
+
<style module>
|
|
259
|
+
.international-example {
|
|
260
|
+
max-width: 500px;
|
|
261
|
+
padding: 1.5rem;
|
|
262
|
+
border: 1px solid #e0e0e0;
|
|
263
|
+
border-radius: 0.5rem;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.form-group {
|
|
267
|
+
margin-bottom: 1rem;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.form-group label {
|
|
271
|
+
display: block;
|
|
272
|
+
margin-bottom: 0.5rem;
|
|
273
|
+
font-weight: 500;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.validation-status {
|
|
277
|
+
margin-top: 1rem;
|
|
278
|
+
padding: 1rem;
|
|
279
|
+
background-color: #f8f9fa;
|
|
280
|
+
border-radius: 0.25rem;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.status-item {
|
|
284
|
+
margin-bottom: 0.5rem;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.valid {
|
|
288
|
+
color: #28a745;
|
|
289
|
+
font-weight: 500;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.invalid {
|
|
293
|
+
color: #dc3545;
|
|
294
|
+
font-weight: 500;
|
|
295
|
+
}
|
|
296
|
+
</style>
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Contact Form Integration
|
|
300
|
+
|
|
301
|
+
```vue
|
|
302
|
+
<script setup lang="ts">
|
|
303
|
+
import { ref, computed } from "vue";
|
|
304
|
+
import { InputPhone } from "@umbra-ui/core";
|
|
305
|
+
|
|
306
|
+
interface ContactForm {
|
|
307
|
+
name: string;
|
|
308
|
+
email: string;
|
|
309
|
+
phone: string;
|
|
310
|
+
message: string;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const form = ref<ContactForm>({
|
|
314
|
+
name: "",
|
|
315
|
+
email: "",
|
|
316
|
+
phone: "",
|
|
317
|
+
message: "",
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
const phoneValid = ref(false);
|
|
321
|
+
|
|
322
|
+
const isFormValid = computed(() => {
|
|
323
|
+
return (
|
|
324
|
+
form.value.name &&
|
|
325
|
+
form.value.email &&
|
|
326
|
+
form.value.phone &&
|
|
327
|
+
phoneValid.value &&
|
|
328
|
+
form.value.message
|
|
329
|
+
);
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
const handlePhoneValid = (valid: boolean) => {
|
|
333
|
+
phoneValid.value = valid;
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const handleSubmit = () => {
|
|
337
|
+
if (isFormValid.value) {
|
|
338
|
+
console.log("Form submitted:", form.value);
|
|
339
|
+
// Handle form submission
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
</script>
|
|
343
|
+
|
|
344
|
+
<template>
|
|
345
|
+
<div class="contact-form">
|
|
346
|
+
<h3>Contact Us</h3>
|
|
347
|
+
|
|
348
|
+
<form @submit.prevent="handleSubmit">
|
|
349
|
+
<div class="form-group">
|
|
350
|
+
<label>Name *</label>
|
|
351
|
+
<input
|
|
352
|
+
v-model="form.name"
|
|
353
|
+
type="text"
|
|
354
|
+
placeholder="Your name"
|
|
355
|
+
required
|
|
356
|
+
/>
|
|
357
|
+
</div>
|
|
358
|
+
|
|
359
|
+
<div class="form-group">
|
|
360
|
+
<label>Email *</label>
|
|
361
|
+
<input
|
|
362
|
+
v-model="form.email"
|
|
363
|
+
type="email"
|
|
364
|
+
placeholder="your@email.com"
|
|
365
|
+
required
|
|
366
|
+
/>
|
|
367
|
+
</div>
|
|
368
|
+
|
|
369
|
+
<div class="form-group">
|
|
370
|
+
<label>Phone Number *</label>
|
|
371
|
+
<InputPhone
|
|
372
|
+
v-model:value="form.phone"
|
|
373
|
+
@update:valid="handlePhoneValid"
|
|
374
|
+
placeholder="Enter your phone number"
|
|
375
|
+
default-country="US"
|
|
376
|
+
/>
|
|
377
|
+
<div v-if="form.phone && !phoneValid" class="error-message">
|
|
378
|
+
Please enter a valid phone number
|
|
379
|
+
</div>
|
|
380
|
+
</div>
|
|
381
|
+
|
|
382
|
+
<div class="form-group">
|
|
383
|
+
<label>Message *</label>
|
|
384
|
+
<textarea
|
|
385
|
+
v-model="form.message"
|
|
386
|
+
placeholder="Your message"
|
|
387
|
+
rows="4"
|
|
388
|
+
required
|
|
389
|
+
></textarea>
|
|
390
|
+
</div>
|
|
391
|
+
|
|
392
|
+
<button type="submit" :disabled="!isFormValid" class="submit-button">
|
|
393
|
+
Send Message
|
|
394
|
+
</button>
|
|
395
|
+
</form>
|
|
396
|
+
</div>
|
|
397
|
+
</template>
|
|
398
|
+
|
|
399
|
+
<style module>
|
|
400
|
+
.contact-form {
|
|
401
|
+
max-width: 600px;
|
|
402
|
+
padding: 2rem;
|
|
403
|
+
border: 1px solid #e0e0e0;
|
|
404
|
+
border-radius: 0.5rem;
|
|
405
|
+
background-color: #fff;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.form-group {
|
|
409
|
+
margin-bottom: 1.5rem;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.form-group label {
|
|
413
|
+
display: block;
|
|
414
|
+
margin-bottom: 0.5rem;
|
|
415
|
+
font-weight: 500;
|
|
416
|
+
color: #333;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.form-group input,
|
|
420
|
+
.form-group textarea {
|
|
421
|
+
width: 100%;
|
|
422
|
+
padding: 0.75rem;
|
|
423
|
+
border: 1px solid #ddd;
|
|
424
|
+
border-radius: 0.25rem;
|
|
425
|
+
font-size: 1rem;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.form-group input:focus,
|
|
429
|
+
.form-group textarea:focus {
|
|
430
|
+
outline: none;
|
|
431
|
+
border-color: #007bff;
|
|
432
|
+
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.error-message {
|
|
436
|
+
color: #dc3545;
|
|
437
|
+
font-size: 0.875rem;
|
|
438
|
+
margin-top: 0.25rem;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.submit-button {
|
|
442
|
+
width: 100%;
|
|
443
|
+
padding: 0.75rem;
|
|
444
|
+
background-color: #007bff;
|
|
445
|
+
color: white;
|
|
446
|
+
border: none;
|
|
447
|
+
border-radius: 0.25rem;
|
|
448
|
+
font-size: 1rem;
|
|
449
|
+
cursor: pointer;
|
|
450
|
+
transition: background-color 0.2s;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.submit-button:hover:not(:disabled) {
|
|
454
|
+
background-color: #0056b3;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.submit-button:disabled {
|
|
458
|
+
background-color: #6c757d;
|
|
459
|
+
cursor: not-allowed;
|
|
460
|
+
}
|
|
461
|
+
</style>
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Different States
|
|
465
|
+
|
|
466
|
+
```vue
|
|
467
|
+
<script setup lang="ts">
|
|
468
|
+
import { ref } from "vue";
|
|
469
|
+
import { InputPhone } from "@umbra-ui/core";
|
|
470
|
+
|
|
471
|
+
const normalPhone = ref("");
|
|
472
|
+
const disabledPhone = ref("(555) 123-4567");
|
|
473
|
+
const readonlyPhone = ref("+1 (555) 987-6543");
|
|
474
|
+
const errorPhone = ref("123");
|
|
475
|
+
</script>
|
|
476
|
+
|
|
477
|
+
<template>
|
|
478
|
+
<div class="states-example">
|
|
479
|
+
<h3>Input States</h3>
|
|
480
|
+
|
|
481
|
+
<div class="state-group">
|
|
482
|
+
<label>Normal State</label>
|
|
483
|
+
<InputPhone
|
|
484
|
+
v-model:value="normalPhone"
|
|
485
|
+
placeholder="Enter phone number"
|
|
486
|
+
state="normal"
|
|
487
|
+
/>
|
|
488
|
+
</div>
|
|
489
|
+
|
|
490
|
+
<div class="state-group">
|
|
491
|
+
<label>Disabled State</label>
|
|
492
|
+
<InputPhone v-model:value="disabledPhone" state="disabled" />
|
|
493
|
+
</div>
|
|
494
|
+
|
|
495
|
+
<div class="state-group">
|
|
496
|
+
<label>Readonly State</label>
|
|
497
|
+
<InputPhone v-model:value="readonlyPhone" state="readonly" />
|
|
498
|
+
</div>
|
|
499
|
+
|
|
500
|
+
<div class="state-group">
|
|
501
|
+
<label>Error State (Invalid Number)</label>
|
|
502
|
+
<InputPhone
|
|
503
|
+
v-model:value="errorPhone"
|
|
504
|
+
placeholder="Enter valid phone number"
|
|
505
|
+
state="normal"
|
|
506
|
+
/>
|
|
507
|
+
</div>
|
|
508
|
+
</div>
|
|
509
|
+
</template>
|
|
510
|
+
|
|
511
|
+
<style module>
|
|
512
|
+
.states-example {
|
|
513
|
+
max-width: 500px;
|
|
514
|
+
padding: 1.5rem;
|
|
515
|
+
border: 1px solid #e0e0e0;
|
|
516
|
+
border-radius: 0.5rem;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
.state-group {
|
|
520
|
+
margin-bottom: 1.5rem;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
.state-group label {
|
|
524
|
+
display: block;
|
|
525
|
+
margin-bottom: 0.5rem;
|
|
526
|
+
font-weight: 500;
|
|
527
|
+
color: #333;
|
|
528
|
+
}
|
|
529
|
+
</style>
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### Country-Specific Examples
|
|
533
|
+
|
|
534
|
+
```vue
|
|
535
|
+
<script setup lang="ts">
|
|
536
|
+
import { ref } from "vue";
|
|
537
|
+
import { InputPhone } from "@umbra-ui/core";
|
|
538
|
+
|
|
539
|
+
const usPhone = ref("");
|
|
540
|
+
const ukPhone = ref("");
|
|
541
|
+
const internationalPhone = ref("");
|
|
542
|
+
|
|
543
|
+
const handleUSPhone = (value: string) => {
|
|
544
|
+
usPhone.value = value;
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
const handleUKPhone = (value: string) => {
|
|
548
|
+
ukPhone.value = value;
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
const handleInternationalPhone = (value: string) => {
|
|
552
|
+
internationalPhone.value = value;
|
|
553
|
+
};
|
|
554
|
+
</script>
|
|
555
|
+
|
|
556
|
+
<template>
|
|
557
|
+
<div class="country-examples">
|
|
558
|
+
<h3>Country-Specific Formatting</h3>
|
|
559
|
+
|
|
560
|
+
<div class="country-group">
|
|
561
|
+
<h4>United States</h4>
|
|
562
|
+
<InputPhone
|
|
563
|
+
v-model:value="usPhone"
|
|
564
|
+
@update:value="handleUSPhone"
|
|
565
|
+
placeholder="Enter US phone number"
|
|
566
|
+
default-country="US"
|
|
567
|
+
:show-country-code="true"
|
|
568
|
+
/>
|
|
569
|
+
<p class="format-info">Format: (555) 123-4567 or +1 (555) 123-4567</p>
|
|
570
|
+
</div>
|
|
571
|
+
|
|
572
|
+
<div class="country-group">
|
|
573
|
+
<h4>United Kingdom</h4>
|
|
574
|
+
<InputPhone
|
|
575
|
+
v-model:value="ukPhone"
|
|
576
|
+
@update:value="handleUKPhone"
|
|
577
|
+
placeholder="Enter UK phone number"
|
|
578
|
+
default-country="GB"
|
|
579
|
+
:show-country-code="true"
|
|
580
|
+
/>
|
|
581
|
+
<p class="format-info">Format: 20 1234 5678 or +44 20 1234 5678</p>
|
|
582
|
+
</div>
|
|
583
|
+
|
|
584
|
+
<div class="country-group">
|
|
585
|
+
<h4>International</h4>
|
|
586
|
+
<InputPhone
|
|
587
|
+
v-model:value="internationalPhone"
|
|
588
|
+
@update:value="handleInternationalPhone"
|
|
589
|
+
placeholder="Enter international phone number"
|
|
590
|
+
default-country="US"
|
|
591
|
+
:allow-international="true"
|
|
592
|
+
:show-country-code="true"
|
|
593
|
+
/>
|
|
594
|
+
<p class="format-info">Format: +[country code] [number]</p>
|
|
595
|
+
</div>
|
|
596
|
+
</div>
|
|
597
|
+
</template>
|
|
598
|
+
|
|
599
|
+
<style module>
|
|
600
|
+
.country-examples {
|
|
601
|
+
max-width: 600px;
|
|
602
|
+
padding: 1.5rem;
|
|
603
|
+
border: 1px solid #e0e0e0;
|
|
604
|
+
border-radius: 0.5rem;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
.country-group {
|
|
608
|
+
margin-bottom: 2rem;
|
|
609
|
+
padding: 1rem;
|
|
610
|
+
border: 1px solid #f0f0f0;
|
|
611
|
+
border-radius: 0.25rem;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
.country-group h4 {
|
|
615
|
+
margin: 0 0 1rem 0;
|
|
616
|
+
color: #333;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
.format-info {
|
|
620
|
+
margin-top: 0.5rem;
|
|
621
|
+
font-size: 0.875rem;
|
|
622
|
+
color: #666;
|
|
623
|
+
font-style: italic;
|
|
624
|
+
}
|
|
625
|
+
</style>
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
## Technical Notes
|
|
629
|
+
|
|
630
|
+
- Phone number validation follows country-specific rules and E.164 international standard
|
|
631
|
+
- Automatic formatting preserves cursor position during input
|
|
632
|
+
- Supports paste operations with proper formatting and validation
|
|
633
|
+
- Input restrictions prevent non-digit characters except formatting symbols
|
|
634
|
+
- Responsive design prevents zoom on mobile devices with proper font sizing
|
|
635
|
+
- Error states are automatically triggered for invalid phone numbers
|
|
636
|
+
- Country detection works for US, UK, and generic international formats
|