glib-web 0.5.98 → 0.6.2

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.
Files changed (204) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +0 -0
  3. package/action.js +167 -167
  4. package/actions/analytics/logEvent.js +0 -0
  5. package/actions/auth/creditCard.js +0 -0
  6. package/actions/auth/restart.js +0 -0
  7. package/actions/auth/saveCsrfToken.js +0 -0
  8. package/actions/cables/push.js +0 -0
  9. package/actions/dialogs/alert.js +0 -0
  10. package/actions/dialogs/notification.js +0 -0
  11. package/actions/dialogs/oauth.js +0 -0
  12. package/actions/dialogs/open.js +0 -0
  13. package/actions/dialogs/options.js +0 -0
  14. package/actions/dialogs/show.js +0 -0
  15. package/actions/forms/submit.js +0 -0
  16. package/actions/http/delete.js +0 -0
  17. package/actions/http/patch.js +0 -0
  18. package/actions/http/post.js +0 -0
  19. package/actions/http/put.js +0 -0
  20. package/actions/panels/scrollTo.js +18 -18
  21. package/actions/panels/scrollToBottom.js +0 -0
  22. package/actions/runMultiple.js +0 -0
  23. package/actions/sheets/select.js +0 -0
  24. package/actions/snackbars/alert.js +0 -0
  25. package/actions/snackbars/select.js +0 -0
  26. package/actions/timeouts/set.js +20 -20
  27. package/actions/windows/close.js +0 -0
  28. package/actions/windows/closeAll.js +0 -0
  29. package/actions/windows/closeWithReload.js +0 -0
  30. package/actions/windows/open.js +0 -0
  31. package/actions/windows/openWeb.js +0 -0
  32. package/actions/windows/refreshState.js +5 -5
  33. package/actions/windows/reload.js +0 -0
  34. package/actions/ws/push.js +0 -0
  35. package/app.vue +180 -180
  36. package/components/_badge.vue +23 -23
  37. package/components/_button.vue +107 -107
  38. package/components/_dropdownMenu.vue +76 -76
  39. package/components/_icon.vue +50 -50
  40. package/components/_message.vue +0 -0
  41. package/components/avatar.vue +18 -18
  42. package/components/banners/alert.vue +0 -0
  43. package/components/banners/select.vue +82 -82
  44. package/components/button.vue +33 -40
  45. package/components/calendar.vue +0 -0
  46. package/components/charts/column.vue +47 -34
  47. package/components/charts/line.vue +67 -65
  48. package/components/chip.vue +51 -26
  49. package/components/component.vue +225 -225
  50. package/components/datetime.vue +0 -0
  51. package/components/fab.vue +0 -0
  52. package/components/fields/_patternText.vue +65 -65
  53. package/components/fields/_select.vue +86 -86
  54. package/components/fields/autocomplete.vue +73 -73
  55. package/components/fields/check.vue +91 -81
  56. package/components/fields/checkGroup.vue +58 -58
  57. package/components/fields/country/countries.js +0 -0
  58. package/components/fields/country/field.vue +0 -0
  59. package/components/fields/country/regions.js +0 -0
  60. package/components/fields/creditCard.vue +22 -13
  61. package/components/fields/date.vue +24 -24
  62. package/components/fields/datetime.vue +0 -0
  63. package/components/fields/dynamicGroup.vue +0 -0
  64. package/components/fields/dynamicSelect.vue +0 -0
  65. package/components/fields/file.vue +0 -0
  66. package/components/fields/googlePlace.vue +0 -0
  67. package/components/fields/hidden.vue +0 -0
  68. package/components/fields/location.vue +198 -198
  69. package/components/fields/newRichText.vue +0 -0
  70. package/components/fields/phone/countries.js +315 -315
  71. package/components/fields/phone/field.vue +351 -351
  72. package/components/fields/phone/sprite.css +1071 -1071
  73. package/components/fields/radio.vue +16 -16
  74. package/components/fields/radioGroup.vue +42 -42
  75. package/components/fields/rating.vue +0 -0
  76. package/components/fields/richText.vue +0 -0
  77. package/components/fields/select.vue +17 -17
  78. package/components/fields/stripe/stripeFields.vue +93 -93
  79. package/components/fields/stripe/stripeIndividualFields.vue +207 -207
  80. package/components/fields/stripeExternalAccount.vue +135 -135
  81. package/components/fields/text.vue +0 -0
  82. package/components/fields/textarea.vue +0 -0
  83. package/components/fields/timeZone.vue +22 -22
  84. package/components/fields/timer.vue +83 -83
  85. package/components/h1.vue +28 -28
  86. package/components/h2.vue +28 -20
  87. package/components/h3.vue +29 -22
  88. package/components/h4.vue +28 -20
  89. package/components/h5.vue +28 -20
  90. package/components/h6.vue +28 -20
  91. package/components/hr.vue +0 -0
  92. package/components/html.vue +0 -0
  93. package/components/icon.vue +25 -25
  94. package/components/image.vue +0 -0
  95. package/components/label.vue +62 -62
  96. package/components/map.vue +0 -0
  97. package/components/markdown.vue +0 -0
  98. package/components/mixins/{chart.js → chart/annotation.js} +73 -73
  99. package/components/mixins/chart/tooltip.js +31 -0
  100. package/components/mixins/events.js +178 -178
  101. package/components/mixins/generic.js +0 -0
  102. package/components/mixins/list/autoload.js +0 -0
  103. package/components/mixins/longClick.js +0 -0
  104. package/components/mixins/scrolling.js +0 -0
  105. package/components/mixins/styles.js +222 -222
  106. package/components/mixins/table/autoload.js +0 -0
  107. package/components/mixins/table/export.js +0 -0
  108. package/components/mixins/table/import.js +0 -0
  109. package/components/mixins/text.js +20 -20
  110. package/components/mixins/tooltip.js +11 -0
  111. package/components/mixins/ws/actionCable.js +48 -48
  112. package/components/mixins/ws/phoenixSocket.js +0 -0
  113. package/components/p.vue +0 -0
  114. package/components/panels/carousel.vue +55 -55
  115. package/components/panels/column.vue +0 -0
  116. package/components/panels/custom.vue +0 -0
  117. package/components/panels/flow.vue +81 -81
  118. package/components/panels/form.vue +130 -130
  119. package/components/panels/horizontal.vue +0 -0
  120. package/components/panels/list.vue +247 -247
  121. package/components/panels/responsive.vue +94 -94
  122. package/components/panels/scroll.vue +0 -0
  123. package/components/panels/split.vue +0 -0
  124. package/components/panels/table.vue +0 -0
  125. package/components/panels/ul.vue +34 -34
  126. package/components/panels/vertical.vue +0 -0
  127. package/components/panels/web.vue +11 -11
  128. package/components/progressbar.vue +36 -36
  129. package/components/spacer.vue +0 -0
  130. package/components/switch.vue +42 -42
  131. package/components/tabBar.vue +68 -68
  132. package/extensions/array.js +0 -0
  133. package/extensions/string.js +21 -21
  134. package/index.js +199 -199
  135. package/keys.js +0 -0
  136. package/nav/appbar.vue +136 -136
  137. package/nav/content.vue +0 -0
  138. package/nav/dialog.vue +127 -127
  139. package/nav/drawer.vue +105 -105
  140. package/nav/drawerButton.vue +31 -31
  141. package/nav/drawerLabel.vue +0 -0
  142. package/nav/sheet.vue +0 -0
  143. package/nav/snackbar.vue +0 -0
  144. package/package.json +44 -44
  145. package/settings.json.example +0 -0
  146. package/static/plugins/alignment/alignment.js +0 -0
  147. package/static/plugins/alignment/alignment.min.js +0 -0
  148. package/static/plugins/beyondgrammar/beyondgrammar.js +0 -0
  149. package/static/plugins/beyondgrammar/beyondgrammar.min.js +0 -0
  150. package/static/plugins/blockcode/blockcode.js +0 -0
  151. package/static/plugins/blockcode/blockcode.min.js +0 -0
  152. package/static/plugins/clips/clips.js +0 -0
  153. package/static/plugins/clips/clips.min.js +0 -0
  154. package/static/plugins/counter/counter.js +0 -0
  155. package/static/plugins/counter/counter.min.js +0 -0
  156. package/static/plugins/definedlinks/definedlinks.js +0 -0
  157. package/static/plugins/definedlinks/definedlinks.min.js +0 -0
  158. package/static/plugins/handle/handle.js +0 -0
  159. package/static/plugins/handle/handle.min.js +0 -0
  160. package/static/plugins/icons/icons.js +0 -0
  161. package/static/plugins/icons/icons.min.js +0 -0
  162. package/static/plugins/imageposition/imageposition.js +0 -0
  163. package/static/plugins/imageposition/imageposition.min.js +0 -0
  164. package/static/plugins/inlineformat/inlineformat.js +0 -0
  165. package/static/plugins/inlineformat/inlineformat.min.js +0 -0
  166. package/static/plugins/removeformat/removeformat.js +0 -0
  167. package/static/plugins/removeformat/removeformat.min.js +0 -0
  168. package/static/plugins/selector/selector.js +0 -0
  169. package/static/plugins/selector/selector.min.js +0 -0
  170. package/static/plugins/specialchars/specialchars.js +0 -0
  171. package/static/plugins/specialchars/specialchars.min.js +0 -0
  172. package/static/plugins/textdirection/textdirection.js +0 -0
  173. package/static/plugins/textdirection/textdirection.min.js +0 -0
  174. package/static/plugins/textexpander/textexpander.js +0 -0
  175. package/static/plugins/textexpander/textexpander.min.js +0 -0
  176. package/static/plugins/underline/underline.js +0 -0
  177. package/static/plugins/underline/underline.min.js +0 -0
  178. package/static/redactorx.css +0 -0
  179. package/static/redactorx.js +0 -0
  180. package/static/redactorx.min.css +0 -0
  181. package/static/redactorx.min.js +0 -0
  182. package/static/redactorx.usm.min.js +0 -0
  183. package/styles/test.sass +0 -0
  184. package/styles/test.scss +0 -0
  185. package/templates/_menu.vue +38 -38
  186. package/templates/comment.vue +202 -202
  187. package/templates/featured.vue +32 -32
  188. package/templates/thumbnail.vue +145 -145
  189. package/templates/unsupported.vue +12 -12
  190. package/utils/app.js +0 -0
  191. package/utils/dom.js +0 -0
  192. package/utils/form.js +0 -0
  193. package/utils/hash.js +0 -0
  194. package/utils/helper.js +0 -0
  195. package/utils/history.js +70 -70
  196. package/utils/http.js +209 -209
  197. package/utils/launch.js +135 -135
  198. package/utils/private/ws.js +0 -0
  199. package/utils/public.js +0 -0
  200. package/utils/settings.js +0 -0
  201. package/utils/storage.js +0 -0
  202. package/utils/type.js +0 -0
  203. package/utils/uploader.js +0 -0
  204. package/utils/url.js +136 -136
@@ -1,351 +1,351 @@
1
- <template>
2
- <div :style="$styles()" :class="classes()">
3
- <div class="country-code">
4
- <v-select
5
- v-model="countryCode"
6
- :items="sortedCountries"
7
- :disabled="spec.readOnly"
8
- :outlined="$classes().includes('outlined')"
9
- :rounded="$classes().includes('rounded')"
10
- :dense="$classes().includes('dense')"
11
- item-text="name"
12
- item-value="iso2"
13
- return-object
14
- @change="onChangeCountryCode"
15
- >
16
- <template v-slot:selection>
17
- <div :class="activeCountry.iso2.toLowerCase()" class="country_flag" />
18
- </template>
19
- <template v-slot:item="data">
20
- <span :class="data.item.iso2.toLowerCase()" class="country_flag" />
21
- <span>{{ data.item.name }} {{ `+${data.item.dialCode}` }}</span>
22
- </template>
23
- </v-select>
24
- </div>
25
- <v-text-field
26
- :id="inputId"
27
- ref="input"
28
- v-model="phone"
29
- class="tel"
30
- :label="spec.label"
31
- :name="fieldName"
32
- :value="spec.value"
33
- :hint="spec.hint"
34
- :placeholder="spec.placeholder"
35
- :maxlength="spec.maxLength || 25"
36
- :disabled="spec.readOnly"
37
- type="tel"
38
- :rules="hiddenDisplay() ? [] : rules"
39
- :prefix="spec.leftText"
40
- :suffix="spec.rightText"
41
- :outlined="$classes().includes('outlined')"
42
- :dense="$classes().includes('dense')"
43
- :rounded="$classes().includes('rounded')"
44
- :autofocus="spec.autoFocus || false"
45
- validate-on-blur
46
- >
47
- </v-text-field>
48
- <input
49
- v-if="spec.readOnly"
50
- type="hidden"
51
- :name="fieldName"
52
- :value="phone"
53
- />
54
- </div>
55
- </template>
56
-
57
- <script>
58
- import PhoneNumber from "awesome-phonenumber";
59
- import allCountries from "./countries";
60
-
61
- function getCountryByIp() {
62
- return fetch("https://ip2c.org/s")
63
- .then(response => response.text())
64
- .then(response => {
65
- const result = (response || "").toString();
66
- if (!result || result[0] !== "1") {
67
- throw new Error("unable to fetch the country");
68
- }
69
- return result.substr(2, 2);
70
- });
71
- }
72
-
73
- export default {
74
- props: {
75
- spec: {
76
- type: Object,
77
- required: true
78
- },
79
- rules: {
80
- type: Array,
81
- default: () => [
82
- v =>
83
- !v ||
84
- /^\+[1-9]([0-9\(\)\-\ ]*)$/.test(v) ||
85
- "Must be a valid international phone number with prefix (e.g. +1 416 555 0134)"
86
- ]
87
- },
88
- disableFetchingCountry: {
89
- type: Boolean,
90
- default: () => false
91
- },
92
- mode: {
93
- type: String,
94
- default: () => ""
95
- },
96
- allCountries: {
97
- type: Array,
98
- default: () => allCountries
99
- },
100
- preferredCountries: {
101
- type: Array,
102
- default: () => []
103
- },
104
- inputId: {
105
- type: String,
106
- default: () => ""
107
- }
108
- },
109
- data() {
110
- return {
111
- phone: "",
112
- activeCountry: { iso2: "" },
113
- selectedIndex: null,
114
- countryCode: null
115
- };
116
- },
117
- computed: {
118
- parsedMode() {
119
- if (this.mode) {
120
- if (!["international", "national"].includes(this.mode)) {
121
- console.error('Invalid value of prop "mode"');
122
- } else {
123
- return this.mode;
124
- }
125
- }
126
- if (!this.phone || this.phone[0] !== "+") {
127
- return "national";
128
- }
129
- return "international";
130
- },
131
- sortedCountries() {
132
- // Sort by preferred countries
133
- const preferredCountries = this.getCountries(
134
- this.preferredCountries
135
- ).map(country => ({ ...country, preferred: true }));
136
- return [...preferredCountries, ...this.allCountries];
137
- },
138
- phoneObject() {
139
- const result = PhoneNumber(
140
- this.phone || "",
141
- this.activeCountry.iso2
142
- ).toJSON();
143
- Object.assign(result, {
144
- isValid: result.valid,
145
- country: this.activeCountry
146
- });
147
- if (!this.phone) {
148
- return {
149
- ...result,
150
- number: {
151
- input: ""
152
- }
153
- };
154
- }
155
- return result;
156
- },
157
- phoneText() {
158
- let key = "input";
159
- if (this.phoneObject.valid) {
160
- key = this.parsedMode;
161
- }
162
- return this.phoneObject.number[key] || "";
163
- }
164
- },
165
- watch: {
166
- phone(val) {
167
- if (val) {
168
- if (val[0] === "+") {
169
- const code = PhoneNumber(val).getRegionCode();
170
- if (code) {
171
- this.activeCountry = this.findCountry(code) || this.activeCountry;
172
- }
173
- }
174
- }
175
- }
176
- },
177
- mounted() {
178
- this.initializeCountry()
179
- .then(() => {
180
- if (!this.phone && this.activeCountry.dialCode) {
181
- this.phone = `+${this.activeCountry.dialCode}`;
182
- }
183
- this.countryCode = this.activeCountry;
184
- })
185
- .catch(console.error);
186
- },
187
- created() {
188
- if (this.spec.value) {
189
- this.phone = this.spec.value.trim();
190
- }
191
- },
192
- methods: {
193
- hiddenDisplay() {
194
- return this.$styles()["display"] == "none";
195
- },
196
- classes() {
197
- return this.$classes().concat(["g-text-field--hintless", "fields-phone"]);
198
- },
199
- initializeCountry() {
200
- return new Promise(resolve => {
201
- // 1. If the phone included prefix (+12), try to get the country and set it
202
- if (this.phone && this.phone[0] === "+") {
203
- const activeCountry = PhoneNumber(this.phone).getRegionCode();
204
- if (activeCountry) {
205
- this.choose(activeCountry);
206
- resolve();
207
- return;
208
- }
209
- }
210
- // 2. Use default country if passed from parent
211
- if (this.spec.defaultCountry) {
212
- const defaultCountry = this.findCountry(this.spec.defaultCountry);
213
- if (defaultCountry) {
214
- this.choose(defaultCountry);
215
- resolve();
216
- return;
217
- }
218
- }
219
- const fallbackCountry =
220
- this.findCountry(this.preferredCountries[0]) || this.allCountries[0];
221
- // 3. Check if fetching country based on user's IP is allowed, set it as the default country
222
- if (!this.disableFetchingCountry) {
223
- getCountryByIp()
224
- .then(res => {
225
- if (this.phone === "") {
226
- this.activeCountry =
227
- this.findCountry(res) || this.activeCountry;
228
- }
229
- })
230
- .catch(error => {
231
- console.warn(error);
232
- // 4. Use the first country from preferred list (if available) or all countries list
233
- this.choose(fallbackCountry);
234
- })
235
- .finally(() => {
236
- resolve();
237
- });
238
- } else {
239
- // 4. Use the first country from preferred list (if available) or all countries list
240
- this.choose(fallbackCountry);
241
- resolve();
242
- }
243
- });
244
- },
245
- // Get ISO2 code from a list of countries
246
- getCountries(list = []) {
247
- return list
248
- .map(countryCode => this.findCountry(countryCode))
249
- .filter(Boolean);
250
- },
251
- findCountry(iso = "") {
252
- return this.allCountries.find(
253
- country => country.iso2 === iso.toUpperCase()
254
- );
255
- },
256
- getItemClass(index, iso2) {
257
- const highlighted = this.selectedIndex === index;
258
- const lastPreferred = index === this.preferredCountries.length - 1;
259
- const preferred = this.preferredCountries.some(
260
- c => c.toUpperCase() === iso2
261
- );
262
- return {
263
- highlighted,
264
- "last-preferred": lastPreferred,
265
- preferred
266
- };
267
- },
268
- choose(country) {
269
- this.activeCountry = country || this.activeCountry || {};
270
- if (
271
- this.phone &&
272
- this.phone[0] === "+" &&
273
- this.activeCountry.iso2 &&
274
- this.phoneObject.number.significant
275
- ) {
276
- // If country is selected & the field has a valid international phone number
277
- this.phone = PhoneNumber(
278
- this.phoneObject.number.significant,
279
- this.activeCountry.iso2
280
- ).getNumber("international");
281
- } else if (
282
- country &&
283
- this.phone &&
284
- (!this.phoneObject.number.significant || this.phone[0] !== "+")
285
- ) {
286
- // If a new country is selected & the field has NO valid international phone number
287
- this.phone = `+${country.dialCode}`;
288
- } else if (country && !this.phone) {
289
- // If a new country is selected & the field has NO value
290
- this.phone = `+${country.dialCode}`;
291
- }
292
- },
293
- reset() {
294
- this.selectedIndex = this.sortedCountries
295
- .map(c => c.iso2)
296
- .indexOf(this.activeCountry.iso2);
297
- },
298
- onChangeCountryCode() {
299
- this.choose(this.countryCode, true);
300
- }
301
- }
302
- };
303
- </script>
304
-
305
- <style src="./sprite.css"></style>
306
- <style lang="scss">
307
- .g-text-field--hintless {
308
- .v-text-field {
309
- .v-text-field__details {
310
- min-height: 0;
311
- margin-bottom: 0;
312
- .v-messages__message {
313
- min-height: 0;
314
- line-height: 14px;
315
- }
316
- }
317
- }
318
- }
319
- .country_flag {
320
- margin-right: 8px;
321
- }
322
- .fields-phone {
323
- display: flex;
324
- align-items: center;
325
- .country-code {
326
- width: 75px;
327
- }
328
- li.last-preferred {
329
- border-bottom: 1px solid #cacaca;
330
- }
331
- .v-text-field {
332
- .v-select__selections {
333
- position: relative;
334
- .country_flag {
335
- position: absolute;
336
- margin-left: 18px;
337
- }
338
- }
339
- &--outlined {
340
- .v-select__selections {
341
- .country_flag {
342
- margin-left: auto;
343
- }
344
- }
345
- }
346
- }
347
- }
348
- .fields-phone.outlined .country-code {
349
- margin-right: 6px;
350
- }
351
- </style>
1
+ <template>
2
+ <div :style="$styles()" :class="classes()">
3
+ <div class="country-code">
4
+ <v-select
5
+ v-model="countryCode"
6
+ :items="sortedCountries"
7
+ :disabled="spec.readOnly"
8
+ :outlined="$classes().includes('outlined')"
9
+ :rounded="$classes().includes('rounded')"
10
+ :dense="$classes().includes('dense')"
11
+ item-text="name"
12
+ item-value="iso2"
13
+ return-object
14
+ @change="onChangeCountryCode"
15
+ >
16
+ <template v-slot:selection>
17
+ <div :class="activeCountry.iso2.toLowerCase()" class="country_flag" />
18
+ </template>
19
+ <template v-slot:item="data">
20
+ <span :class="data.item.iso2.toLowerCase()" class="country_flag" />
21
+ <span>{{ data.item.name }} {{ `+${data.item.dialCode}` }}</span>
22
+ </template>
23
+ </v-select>
24
+ </div>
25
+ <v-text-field
26
+ :id="inputId"
27
+ ref="input"
28
+ v-model="phone"
29
+ class="tel"
30
+ :label="spec.label"
31
+ :name="fieldName"
32
+ :value="spec.value"
33
+ :hint="spec.hint"
34
+ :placeholder="spec.placeholder"
35
+ :maxlength="spec.maxLength || 25"
36
+ :disabled="spec.readOnly"
37
+ type="tel"
38
+ :rules="hiddenDisplay() ? [] : rules"
39
+ :prefix="spec.leftText"
40
+ :suffix="spec.rightText"
41
+ :outlined="$classes().includes('outlined')"
42
+ :dense="$classes().includes('dense')"
43
+ :rounded="$classes().includes('rounded')"
44
+ :autofocus="spec.autoFocus || false"
45
+ validate-on-blur
46
+ >
47
+ </v-text-field>
48
+ <input
49
+ v-if="spec.readOnly"
50
+ type="hidden"
51
+ :name="fieldName"
52
+ :value="phone"
53
+ />
54
+ </div>
55
+ </template>
56
+
57
+ <script>
58
+ import PhoneNumber from "awesome-phonenumber";
59
+ import allCountries from "./countries";
60
+
61
+ function getCountryByIp() {
62
+ return fetch("https://ip2c.org/s")
63
+ .then(response => response.text())
64
+ .then(response => {
65
+ const result = (response || "").toString();
66
+ if (!result || result[0] !== "1") {
67
+ throw new Error("unable to fetch the country");
68
+ }
69
+ return result.substr(2, 2);
70
+ });
71
+ }
72
+
73
+ export default {
74
+ props: {
75
+ spec: {
76
+ type: Object,
77
+ required: true
78
+ },
79
+ rules: {
80
+ type: Array,
81
+ default: () => [
82
+ v =>
83
+ !v ||
84
+ /^\+[1-9]([0-9\(\)\-\ ]*)$/.test(v) ||
85
+ "Must be a valid international phone number with prefix (e.g. +1 416 555 0134)"
86
+ ]
87
+ },
88
+ disableFetchingCountry: {
89
+ type: Boolean,
90
+ default: () => false
91
+ },
92
+ mode: {
93
+ type: String,
94
+ default: () => ""
95
+ },
96
+ allCountries: {
97
+ type: Array,
98
+ default: () => allCountries
99
+ },
100
+ preferredCountries: {
101
+ type: Array,
102
+ default: () => []
103
+ },
104
+ inputId: {
105
+ type: String,
106
+ default: () => ""
107
+ }
108
+ },
109
+ data() {
110
+ return {
111
+ phone: "",
112
+ activeCountry: { iso2: "" },
113
+ selectedIndex: null,
114
+ countryCode: null
115
+ };
116
+ },
117
+ computed: {
118
+ parsedMode() {
119
+ if (this.mode) {
120
+ if (!["international", "national"].includes(this.mode)) {
121
+ console.error('Invalid value of prop "mode"');
122
+ } else {
123
+ return this.mode;
124
+ }
125
+ }
126
+ if (!this.phone || this.phone[0] !== "+") {
127
+ return "national";
128
+ }
129
+ return "international";
130
+ },
131
+ sortedCountries() {
132
+ // Sort by preferred countries
133
+ const preferredCountries = this.getCountries(
134
+ this.preferredCountries
135
+ ).map(country => ({ ...country, preferred: true }));
136
+ return [...preferredCountries, ...this.allCountries];
137
+ },
138
+ phoneObject() {
139
+ const result = PhoneNumber(
140
+ this.phone || "",
141
+ this.activeCountry.iso2
142
+ ).toJSON();
143
+ Object.assign(result, {
144
+ isValid: result.valid,
145
+ country: this.activeCountry
146
+ });
147
+ if (!this.phone) {
148
+ return {
149
+ ...result,
150
+ number: {
151
+ input: ""
152
+ }
153
+ };
154
+ }
155
+ return result;
156
+ },
157
+ phoneText() {
158
+ let key = "input";
159
+ if (this.phoneObject.valid) {
160
+ key = this.parsedMode;
161
+ }
162
+ return this.phoneObject.number[key] || "";
163
+ }
164
+ },
165
+ watch: {
166
+ phone(val) {
167
+ if (val) {
168
+ if (val[0] === "+") {
169
+ const code = PhoneNumber(val).getRegionCode();
170
+ if (code) {
171
+ this.activeCountry = this.findCountry(code) || this.activeCountry;
172
+ }
173
+ }
174
+ }
175
+ }
176
+ },
177
+ mounted() {
178
+ this.initializeCountry()
179
+ .then(() => {
180
+ if (!this.phone && this.activeCountry.dialCode) {
181
+ this.phone = `+${this.activeCountry.dialCode}`;
182
+ }
183
+ this.countryCode = this.activeCountry;
184
+ })
185
+ .catch(console.error);
186
+ },
187
+ created() {
188
+ if (this.spec.value) {
189
+ this.phone = this.spec.value.trim();
190
+ }
191
+ },
192
+ methods: {
193
+ hiddenDisplay() {
194
+ return this.$styles()["display"] == "none";
195
+ },
196
+ classes() {
197
+ return this.$classes().concat(["g-text-field--hintless", "fields-phone"]);
198
+ },
199
+ initializeCountry() {
200
+ return new Promise(resolve => {
201
+ // 1. If the phone included prefix (+12), try to get the country and set it
202
+ if (this.phone && this.phone[0] === "+") {
203
+ const activeCountry = PhoneNumber(this.phone).getRegionCode();
204
+ if (activeCountry) {
205
+ this.choose(activeCountry);
206
+ resolve();
207
+ return;
208
+ }
209
+ }
210
+ // 2. Use default country if passed from parent
211
+ if (this.spec.defaultCountry) {
212
+ const defaultCountry = this.findCountry(this.spec.defaultCountry);
213
+ if (defaultCountry) {
214
+ this.choose(defaultCountry);
215
+ resolve();
216
+ return;
217
+ }
218
+ }
219
+ const fallbackCountry =
220
+ this.findCountry(this.preferredCountries[0]) || this.allCountries[0];
221
+ // 3. Check if fetching country based on user's IP is allowed, set it as the default country
222
+ if (!this.disableFetchingCountry) {
223
+ getCountryByIp()
224
+ .then(res => {
225
+ if (this.phone === "") {
226
+ this.activeCountry =
227
+ this.findCountry(res) || this.activeCountry;
228
+ }
229
+ })
230
+ .catch(error => {
231
+ console.warn(error);
232
+ // 4. Use the first country from preferred list (if available) or all countries list
233
+ this.choose(fallbackCountry);
234
+ })
235
+ .finally(() => {
236
+ resolve();
237
+ });
238
+ } else {
239
+ // 4. Use the first country from preferred list (if available) or all countries list
240
+ this.choose(fallbackCountry);
241
+ resolve();
242
+ }
243
+ });
244
+ },
245
+ // Get ISO2 code from a list of countries
246
+ getCountries(list = []) {
247
+ return list
248
+ .map(countryCode => this.findCountry(countryCode))
249
+ .filter(Boolean);
250
+ },
251
+ findCountry(iso = "") {
252
+ return this.allCountries.find(
253
+ country => country.iso2 === iso.toUpperCase()
254
+ );
255
+ },
256
+ getItemClass(index, iso2) {
257
+ const highlighted = this.selectedIndex === index;
258
+ const lastPreferred = index === this.preferredCountries.length - 1;
259
+ const preferred = this.preferredCountries.some(
260
+ c => c.toUpperCase() === iso2
261
+ );
262
+ return {
263
+ highlighted,
264
+ "last-preferred": lastPreferred,
265
+ preferred
266
+ };
267
+ },
268
+ choose(country) {
269
+ this.activeCountry = country || this.activeCountry || {};
270
+ if (
271
+ this.phone &&
272
+ this.phone[0] === "+" &&
273
+ this.activeCountry.iso2 &&
274
+ this.phoneObject.number.significant
275
+ ) {
276
+ // If country is selected & the field has a valid international phone number
277
+ this.phone = PhoneNumber(
278
+ this.phoneObject.number.significant,
279
+ this.activeCountry.iso2
280
+ ).getNumber("international");
281
+ } else if (
282
+ country &&
283
+ this.phone &&
284
+ (!this.phoneObject.number.significant || this.phone[0] !== "+")
285
+ ) {
286
+ // If a new country is selected & the field has NO valid international phone number
287
+ this.phone = `+${country.dialCode}`;
288
+ } else if (country && !this.phone) {
289
+ // If a new country is selected & the field has NO value
290
+ this.phone = `+${country.dialCode}`;
291
+ }
292
+ },
293
+ reset() {
294
+ this.selectedIndex = this.sortedCountries
295
+ .map(c => c.iso2)
296
+ .indexOf(this.activeCountry.iso2);
297
+ },
298
+ onChangeCountryCode() {
299
+ this.choose(this.countryCode, true);
300
+ }
301
+ }
302
+ };
303
+ </script>
304
+
305
+ <style src="./sprite.css"></style>
306
+ <style lang="scss">
307
+ .g-text-field--hintless {
308
+ .v-text-field {
309
+ .v-text-field__details {
310
+ min-height: 0;
311
+ margin-bottom: 0;
312
+ .v-messages__message {
313
+ min-height: 0;
314
+ line-height: 14px;
315
+ }
316
+ }
317
+ }
318
+ }
319
+ .country_flag {
320
+ margin-right: 8px;
321
+ }
322
+ .fields-phone {
323
+ display: flex;
324
+ align-items: center;
325
+ .country-code {
326
+ width: 75px;
327
+ }
328
+ li.last-preferred {
329
+ border-bottom: 1px solid #cacaca;
330
+ }
331
+ .v-text-field {
332
+ .v-select__selections {
333
+ position: relative;
334
+ .country_flag {
335
+ position: absolute;
336
+ margin-left: 18px;
337
+ }
338
+ }
339
+ &--outlined {
340
+ .v-select__selections {
341
+ .country_flag {
342
+ margin-left: auto;
343
+ }
344
+ }
345
+ }
346
+ }
347
+ }
348
+ .fields-phone.outlined .country-code {
349
+ margin-right: 6px;
350
+ }
351
+ </style>