srcdev-nuxt-forms 0.0.23 → 0.2.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.
Files changed (64) hide show
  1. package/.prettierrc +2 -1
  2. package/LICENSE +21 -0
  3. package/assets/styles/forms/index.css +1 -0
  4. package/assets/styles/forms/themes/_error.css +9 -0
  5. package/assets/styles/forms/themes/_ghost.css +11 -0
  6. package/assets/styles/forms/themes/_primary.css +11 -1
  7. package/assets/styles/forms/themes/_secondary.css +13 -0
  8. package/assets/styles/forms/themes/_success.css +12 -0
  9. package/assets/styles/forms/themes/_tertiary.css +11 -0
  10. package/assets/styles/forms/themes/_warning.css +11 -0
  11. package/assets/styles/forms/themes/index.css +5 -0
  12. package/assets/styles/forms/utils/_a11y.css +5 -0
  13. package/assets/styles/forms/utils/index.css +1 -0
  14. package/assets/styles/forms/variables/_theme.css +56 -2
  15. package/assets/styles/variables/colors/_gray.css +1 -0
  16. package/assets/styles/variables/colors/_orange.css +1 -1
  17. package/assets/styles/variables/colors/_red.css +1 -1
  18. package/components/forms/c12/prop-validators/index.ts +13 -0
  19. package/components/forms/c12/utils.ts +14 -0
  20. package/components/forms/c12/validation-patterns/en.json +13 -1
  21. package/components/forms/form-errors/InputError.vue +132 -0
  22. package/components/forms/input-button/InputButtonCore.vue +370 -0
  23. package/components/forms/input-button/variants/InputButtonConfirm.vue +78 -0
  24. package/components/forms/input-button/variants/InputButtonSubmit.vue +74 -0
  25. package/components/forms/input-checkbox/InputCheckboxCore.vue +407 -0
  26. package/components/forms/input-checkbox/InputCheckboxWithLabel.vue +125 -0
  27. package/components/forms/input-checkbox/variants/MultipleCheckboxes.vue +194 -0
  28. package/components/forms/input-checkbox/variants/SingleCheckbox.vue +157 -0
  29. package/components/forms/input-radio/InputRadioCore.vue +226 -0
  30. package/components/forms/input-radio/InputRadioWithLabel.vue +118 -0
  31. package/components/forms/input-radio/variants/MultipleRadio.vue +183 -0
  32. package/components/forms/input-radio/variants/SingleRadio.vue +131 -0
  33. package/components/forms/input-range/InputRangeCore.vue +171 -0
  34. package/components/forms/input-range/variants/InputRangeDefault.vue +131 -0
  35. package/components/forms/input-text/InputTextCore.vue +115 -79
  36. package/components/forms/input-text/variants/material/InputEmailMaterial.vue +72 -0
  37. package/components/forms/input-text/variants/material/InputPasswordMaterial.vue +114 -0
  38. package/components/forms/input-text/variants/material/InputTextMaterial.vue +68 -0
  39. package/components/forms/input-text/variants/material/InputTextMaterialCore.vue +313 -0
  40. package/components/forms/input-textarea/InputTextareaCore.vue +170 -0
  41. package/components/forms/input-textarea/variants/material/InputTextareaMaterial.vue +75 -0
  42. package/components/forms/input-textarea/variants/material/InputTextareaMaterialCore.vue +290 -0
  43. package/components/forms/ui/FormField.vue +7 -2
  44. package/components/forms/ui/FormWrapper.vue +2 -2
  45. package/components/ui/content-grid/ContentGrid.vue +85 -0
  46. package/composables/useErrorMessages.ts +21 -9
  47. package/composables/useFormControl.ts +171 -41
  48. package/layouts/default.vue +28 -3
  49. package/nuxt.config.ts +26 -3
  50. package/package.json +9 -6
  51. package/pages/forms/examples/buttons/index.vue +155 -0
  52. package/pages/forms/examples/material/text-fields.vue +372 -0
  53. package/pages/index.vue +2 -70
  54. package/pages/limit-text.vue +43 -0
  55. package/server/api/places/list.get.ts +23 -0
  56. package/server/api/textFields.post.ts +37 -0
  57. package/server/api/utils/index.get.ts +20 -0
  58. package/server/data/places/cities.json +37 -0
  59. package/server/data/places/countries.json +55 -0
  60. package/server/data/utils/title.json +49 -0
  61. package/types/types.forms.ts +38 -13
  62. package/types/types.places.ts +8 -0
  63. package/components/forms/input-text/InputTextField.vue +0 -22
  64. package/components/forms/input-text/variants/InputTextMaterial.vue +0 -192
@@ -0,0 +1,372 @@
1
+ <template>
2
+ <div>
3
+ <NuxtLayout name="default">
4
+ <template #layout-content>
5
+ <div>
6
+ <h1>Material UI text fields ({{ compact ? 'compact' : 'default' }})</h1>
7
+ <ul class="flex-group">
8
+ <li>
9
+ <InputButtonSubmit type="button" @click.stop.prevent="swapCompact(false)" button-text="Use Default UI" theme="secondary" size="normal" />
10
+ </li>
11
+ <li>
12
+ <InputButtonSubmit type="button" @click.stop.prevent="swapCompact(true)" button-text="Use Compact UI" theme="secondary" size="normal" />
13
+ </li>
14
+ </ul>
15
+
16
+ <p>Example test fields in default material UI</p>
17
+ <p>Use 'test@test.com' to trigger server errors</p>
18
+ </div>
19
+ <ContentGrid>
20
+ <template #slot1>
21
+ <FormWrapper width="medium">
22
+ <template #default>
23
+ <ClientOnly>
24
+ <form class="form-wrapper" @submit.stop.prevent="submitForm()">
25
+ <div aria-live="assertive" id="aria-live-message"></div>
26
+ <FormField width="wide" :has-gutter="false">
27
+ <template #default>
28
+ <InputEmailMaterial
29
+ id="emailAddress"
30
+ name="emailAddress"
31
+ validation="emailaddress"
32
+ :required="true"
33
+ :c12="{
34
+ label: 'Your Email Address',
35
+ placeholder: 'eg. joe@example.com',
36
+ errorMessage: 'Please enter a valid email address',
37
+ }"
38
+ v-model="formData"
39
+ theme="secondary"
40
+ :compact
41
+ />
42
+ </template>
43
+ </FormField>
44
+
45
+ <FormField width="wide" :has-gutter="false">
46
+ <template #default>
47
+ <InputTextMaterial
48
+ id="username"
49
+ name="username"
50
+ validation="username"
51
+ :required="true"
52
+ :c12="{
53
+ label: 'Your Username',
54
+ placeholder: 'eg. YourUserName',
55
+ errorMessage: 'Please enter a valid username',
56
+ }"
57
+ v-model="formData"
58
+ theme="secondary"
59
+ :compact
60
+ />
61
+ </template>
62
+ </FormField>
63
+
64
+ <FormField width="wide" :has-gutter="false">
65
+ <template #default>
66
+ <InputPasswordMaterial
67
+ id="password"
68
+ name="password"
69
+ validation="password"
70
+ :required="true"
71
+ :c12="{
72
+ label: 'Password',
73
+ placeholder: 'eg. Your5illYPa55w0rd',
74
+ errorMessage: 'Please enter a valid password',
75
+ }"
76
+ v-model="formData"
77
+ theme="secondary"
78
+ :compact
79
+ />
80
+ </template>
81
+ </FormField>
82
+
83
+ <FormField width="wide" :has-gutter="false">
84
+ <template #default>
85
+ <InputTextareaMaterial
86
+ id="message"
87
+ name="message"
88
+ validation="message"
89
+ :required="true"
90
+ :c12="{
91
+ label: 'Message',
92
+ placeholder: 'eg. Type something here',
93
+ errorMessage: 'Bad characters in message',
94
+ }"
95
+ v-model="formData"
96
+ theme="secondary"
97
+ :compact
98
+ />
99
+ </template>
100
+ </FormField>
101
+
102
+ <FormField width="wide" :has-gutter="false">
103
+ <template #default>
104
+ <InputRangeDefault
105
+ id="score"
106
+ name="score"
107
+ :min="0"
108
+ :max="100"
109
+ :step="1"
110
+ :required="true"
111
+ validation="positiveNumber0to100"
112
+ :c12="{
113
+ label: 'Score between 0 & 100',
114
+ placeholder: 'eg. What\'s your score?',
115
+ errorMessage: 'Score between 0 & 100',
116
+ }"
117
+ v-model="formData"
118
+ theme="secondary"
119
+ >
120
+ <template #description>
121
+ <p class="label-description">This is a description of what the user is required to do</p>
122
+ </template>
123
+ <template #left>&lt;</template>
124
+ <template #right>&gt;</template>
125
+ </InputRangeDefault>
126
+ </template>
127
+ </FormField>
128
+
129
+ <FormField v-if="citiesData !== null" width="wide" :has-gutter="false">
130
+ <template #default>
131
+ <MultipleCheckboxes
132
+ id="cities"
133
+ name="cities"
134
+ legend="Choose a location"
135
+ :required="true"
136
+ :c12="{
137
+ label: 'Check all Cities you like',
138
+ placeholder: 'eg. Type something here',
139
+ errorMessage: 'Please choose at least 1 location',
140
+ }"
141
+ v-model="formData"
142
+ v-model:fieldData="citiesData"
143
+ theme="secondary"
144
+ size="normal"
145
+ checkbox-style="check"
146
+ checkbox-appearance="with-decorator"
147
+ >
148
+ <template #description>
149
+ <p class="label-description">This is description: optionsLayout = 'equal-widths'</p>
150
+ </template>
151
+ </MultipleCheckboxes>
152
+ </template>
153
+ </FormField>
154
+
155
+ <FormField v-if="countriesData !== null" width="wide" :has-gutter="false">
156
+ <template #default>
157
+ <MultipleCheckboxes
158
+ id="countries"
159
+ name="countries"
160
+ legend="Choose a country"
161
+ :required="true"
162
+ :c12="{
163
+ label: 'Check all countries you like',
164
+ placeholder: 'eg. Choose some locations',
165
+ errorMessage: 'Please select a country',
166
+ }"
167
+ v-model="formData"
168
+ v-model:fieldData="countriesData"
169
+ theme="secondary"
170
+ size="normal"
171
+ options-layout="inline"
172
+ checkbox-style="cross"
173
+ checkbox-appearance="with-decorator"
174
+ >
175
+ <template #description>
176
+ <p class="label-description">This is description: optionsLayout = 'inline'</p>
177
+ </template>
178
+ </MultipleCheckboxes>
179
+ </template>
180
+ </FormField>
181
+
182
+ <FormField v-if="titleData !== null" width="wide" :has-gutter="false">
183
+ <template #default>
184
+ <MultipleRadio
185
+ id="title"
186
+ name="title"
187
+ legend="Choose a title"
188
+ :required="true"
189
+ :c12="{
190
+ label: 'Check all title you like',
191
+ placeholder: 'eg. Choose some title',
192
+ errorMessage: 'Please select a title',
193
+ }"
194
+ v-model="formData"
195
+ v-model:fieldData="titleData"
196
+ theme="secondary"
197
+ size="normal"
198
+ options-layout="equal-widths"
199
+ radio-appearance="with-decorator"
200
+ >
201
+ <template #description>
202
+ <p class="label-description">This is description: optionsLayout = 'equal-widths'</p>
203
+ </template>
204
+ </MultipleRadio>
205
+ </template>
206
+ </FormField>
207
+
208
+ <FormField width="wide" :has-gutter="false">
209
+ <template #default>
210
+ <SingleCheckbox
211
+ id="terms"
212
+ name="terms"
213
+ legend="Accept terms and conditions"
214
+ :required="true"
215
+ :c12="{
216
+ label: 'Accept terms and conditions',
217
+ placeholder: 'eg. Type something here',
218
+ errorMessage: 'Please accept our terms and conditions',
219
+ }"
220
+ v-model="formData"
221
+ theme="secondary"
222
+ size="normal"
223
+ checkbox-appearance="with-decorator"
224
+ checkbox-style="check"
225
+ >
226
+ <template #description>
227
+ <p class="label-description">This is a description of what the user is required to do</p>
228
+ </template>
229
+ </SingleCheckbox>
230
+ </template>
231
+ </FormField>
232
+
233
+ <FormField width="wide" :has-gutter="false">
234
+ <template #default>
235
+ <InputButtonSubmit type="button" @click.stop.prevent="submitForm()" :is-pending="false" :readonly="submitDisabled" button-text="Submit" theme="secondary" size="medium" />
236
+ </template>
237
+ </FormField>
238
+ </form>
239
+ </ClientOnly>
240
+ </template>
241
+ </FormWrapper>
242
+ </template>
243
+ <template #slot2>
244
+ <ClientOnly>
245
+ <p>Client only content</p>
246
+ <pre>
247
+ {{ formData }}
248
+ </pre>
249
+ </ClientOnly>
250
+ </template>
251
+ </ContentGrid>
252
+ </template>
253
+ </NuxtLayout>
254
+ </div>
255
+ </template>
256
+
257
+ <script setup lang="ts">
258
+ import type { IFieldsInitialState, IOptionsConfig, IFormMultipleOptions } from '@/types/types.forms';
259
+
260
+ definePageMeta({
261
+ layout: false,
262
+ });
263
+
264
+ useHead({
265
+ title: 'Text Field Example',
266
+ meta: [{ name: 'description', content: 'Homepage' }],
267
+ bodyAttrs: {
268
+ class: '',
269
+ },
270
+ });
271
+
272
+ const compact = ref(false);
273
+ const swapCompact = (newStyle: boolean) => {
274
+ compact.value = newStyle;
275
+ };
276
+
277
+ /*
278
+ * Fetch some sample data
279
+ **/
280
+ const { data: citiesData } = await useFetch<IFormMultipleOptions>('/api/places/list?category=cities');
281
+ const { data: countriesData } = await useFetch<IFormMultipleOptions>('/api/places/list?category=countries');
282
+ const { data: titleData } = await useFetch<IFormMultipleOptions>('/api/utils?category=title');
283
+
284
+ /*
285
+ * Setup forms
286
+ */
287
+ const fieldsInitialState = ref<IFieldsInitialState>({
288
+ // emailAddress: "simon@simon.com",
289
+ // emailAddress: "test@test.com",
290
+ emailAddress: '',
291
+ // username: "",
292
+ username: '',
293
+ // password: "!+Password123",
294
+ password: '',
295
+ message: '',
296
+ // message: 'This is test 1234567890,.<>?@;:',
297
+ score: 50,
298
+ cities: [],
299
+ countries: [],
300
+ title: [],
301
+ terms: false,
302
+ });
303
+
304
+ // Setup formData
305
+ const { formData, initFormData, getErrorCount, updateErrorMessages, formIsValid, submitDisabled, useApiErrors } = useFormControl();
306
+ await initFormData(fieldsInitialState);
307
+
308
+ async function postFormData() {
309
+ try {
310
+ const data = await $fetch('/api/textFields', {
311
+ method: 'post',
312
+ body: formData.value.data,
313
+ onResponse({ response }) {
314
+ if (response.status === 400) {
315
+ console.log('onResponse', response);
316
+ console.log(response.status);
317
+
318
+ useApiErrors(response._data.data.errors);
319
+ // for (const [key, message] of Object.entries(response._data.data.errors)) {
320
+ // console.log(`${key}: ${message}`);
321
+ // updateErrorMessages(key, message);
322
+ // }
323
+ }
324
+ if (response.status === 200) {
325
+ formData.value.isPending = false;
326
+ formData.value.submitSuccess = true;
327
+ }
328
+ },
329
+ });
330
+ console.log('3: Finished data', data);
331
+ // return data;
332
+ } catch (error) {
333
+ console.warn('2: An error occured posting form data', error);
334
+ }
335
+ }
336
+
337
+ const submitForm = async () => {
338
+ getErrorCount(true);
339
+
340
+ if (formIsValid.value) {
341
+ formData.value.isPending = true;
342
+ formData.value.submitDisabled = true;
343
+ console.log('Form is good - post it!');
344
+
345
+ postFormData();
346
+
347
+ // formData.value.errorMessages['emailAddress'] = {
348
+ // useCustomError: true,
349
+ // message: 'This is a custom error message',
350
+ // };
351
+
352
+ // executePost();
353
+ } else {
354
+ console.warn('Form has errors');
355
+ }
356
+ };
357
+ </script>
358
+
359
+ <style lang="css">
360
+ .flex-group {
361
+ align-items: flex-start;
362
+ display: flex;
363
+ flex-wrap: wrap;
364
+ gap: 24px;
365
+ margin-bottom: 32px;
366
+ }
367
+
368
+ ul.flex-group {
369
+ list-style-type: none;
370
+ padding: 0;
371
+ }
372
+ </style>
package/pages/index.vue CHANGED
@@ -3,53 +3,16 @@
3
3
  <NuxtLayout name="default">
4
4
  <template #layout-content>
5
5
  <div>
6
- <h1>Sample form page</h1>
6
+ <h1>Sample form page pages</h1>
7
7
 
8
- <FormWrapper width="medium">
9
- <template #default>
10
- <form @submit.prevent="isPending">
11
- <p>Form content</p>
12
- <FormField width="wide" :has-gutter="true">
13
- <template #default>
14
- <p>Input text</p>
15
- <InputTextMaterial
16
- id="username"
17
- name="username"
18
- type="text"
19
- validation="username"
20
- :required="true"
21
- :c12="{
22
- label: 'Choose Username',
23
- placeholder: 'eg. YourUserName',
24
- errorMessage: 'Please enter a valid username',
25
- }"
26
- v-model="formData"
27
- />
28
- </template>
29
- </FormField>
30
- <input
31
- type="submit"
32
- @click.prevent="isPending"
33
- value="Submit"
34
- />
35
- </form>
36
- </template>
37
- </FormWrapper>
8
+ <p>Example test fields in default material UI</p>
38
9
  </div>
39
- <ClientOnly>
40
- <p>Client only content</p>
41
- <pre>
42
- {{ formData }}
43
- </pre>
44
- </ClientOnly>
45
10
  </template>
46
11
  </NuxtLayout>
47
12
  </div>
48
13
  </template>
49
14
 
50
15
  <script setup lang="ts">
51
- import type { IFieldsInitialState, IOptionsConfig } from '@/types/types.forms';
52
-
53
16
  definePageMeta({
54
17
  layout: false,
55
18
  });
@@ -61,37 +24,6 @@ useHead({
61
24
  class: '',
62
25
  },
63
26
  });
64
-
65
- /*
66
- * Setup forms
67
- */
68
- const fieldsInitialState = ref<IFieldsInitialState>({
69
- username: '',
70
- });
71
-
72
- // Setup formData
73
- const {
74
- formData,
75
- initFormData,
76
- getErrorCount,
77
- updateCustomErrors,
78
- resetForm,
79
- formIsValid,
80
- showErrors,
81
- } = useFormControl(fieldsInitialState);
82
-
83
- await initFormData();
84
-
85
- const isPending = async () => {
86
- formData.value.isPending = true;
87
- await getErrorCount();
88
-
89
- if (formIsValid.value) {
90
- console.log('Form is good - post it!');
91
- } else {
92
- console.warn('Form has errors');
93
- }
94
- };
95
27
  </script>
96
28
 
97
29
  <style lang="css">
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <div class="wrapper">
3
+ <div class="text-wrapper">
4
+ <p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
5
+ </div>
6
+ <div class="text-wrapper">
7
+ <p>Nisi harum impedit, expedita eius doloremque dicta obcaecati tempora dolorem eum fuga deserunt minus facere error mollitia pariatur cum tempore, reiciendis molestiae?</p>
8
+ </div>
9
+ <div class="text-wrapper">
10
+ <p>
11
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi harum impedit, expedita eius doloremque dicta obcaecati tempora dolorem eum fuga deserunt minus facere error mollitia pariatur cum
12
+ tempore, reiciendis molestiae?
13
+ </p>
14
+ </div>
15
+ </div>
16
+ </template>
17
+ <script setup lang="ts">
18
+ definePageMeta({
19
+ layout: false,
20
+ });
21
+ </script>
22
+ <style lang="css">
23
+ .wrapper {
24
+ display: grid;
25
+ grid-template-columns: 1fr 1fr 1fr;
26
+ gap: 20px;
27
+ }
28
+
29
+ .text-wrapper {
30
+ max-height: 100px;
31
+ width: 200px;
32
+ padding: 20px;
33
+ outline: 1px solid black;
34
+
35
+ p {
36
+ display: -webkit-box;
37
+ -webkit-box-orient: vertical;
38
+ line-clamp: 3;
39
+ -webkit-line-clamp: 3;
40
+ overflow: hidden;
41
+ }
42
+ }
43
+ </style>
@@ -0,0 +1,23 @@
1
+ import cities from '../../data/places/cities.json';
2
+ import countries from '../../data/places/countries.json';
3
+
4
+ export default defineEventHandler(async (event) => {
5
+ const sleep = async (ms: number) => {
6
+ return new Promise((resolve) => setTimeout(resolve, ms));
7
+ };
8
+
9
+ const query = getQuery(event);
10
+
11
+ let timeout = 0;
12
+ if (typeof query.delay !== 'undefined') {
13
+ timeout = Number(query.delay);
14
+ }
15
+
16
+ await sleep(timeout);
17
+
18
+ if (query.category === 'cities') {
19
+ return cities;
20
+ } else if (query.category === 'countries') {
21
+ return countries;
22
+ }
23
+ });
@@ -0,0 +1,37 @@
1
+ import { createError } from 'h3';
2
+
3
+ export default defineEventHandler(async (event: any) => {
4
+ const body = await readBody<{ emailAddress: string; password: string; username: string }>(event);
5
+
6
+ const { emailAddress, password, username } = body;
7
+
8
+ let throwError = false;
9
+
10
+ if (emailAddress === 'test@test.com') {
11
+ throwError = true;
12
+ }
13
+
14
+ const response = {
15
+ status: 200,
16
+ statusText: 'success',
17
+ };
18
+
19
+ // set some other response status cde
20
+ // setResponseStatus(event, 202)
21
+
22
+ // Throw some server side errors
23
+ if (throwError) {
24
+ throw createError({
25
+ statusCode: 400,
26
+ statusMessage: 'error',
27
+ data: {
28
+ errors: {
29
+ emailAddress: 'Email address already registered',
30
+ username: 'Username already registered',
31
+ password: ['Password is too weak', 'Password is too short'],
32
+ },
33
+ },
34
+ });
35
+ }
36
+ return response;
37
+ });
@@ -0,0 +1,20 @@
1
+ import title from '../../data/utils/title.json';
2
+
3
+ export default defineEventHandler(async (event) => {
4
+ const sleep = async (ms: number) => {
5
+ return new Promise((resolve) => setTimeout(resolve, ms));
6
+ };
7
+
8
+ const query = getQuery(event);
9
+
10
+ let timeout = 0;
11
+ if (typeof query.delay !== 'undefined') {
12
+ timeout = Number(query.delay);
13
+ }
14
+
15
+ await sleep(timeout);
16
+
17
+ if (query.category === 'title') {
18
+ return title;
19
+ }
20
+ });
@@ -0,0 +1,37 @@
1
+ {
2
+ "data": [
3
+ {
4
+ "id": "bath",
5
+ "name": "cities",
6
+ "value": "cities-12",
7
+ "label": "Bath"
8
+ },
9
+ {
10
+ "id": "bristol",
11
+ "name": "cities",
12
+ "value": "cities-23",
13
+ "label": "Bristol"
14
+ },
15
+ {
16
+ "id": "london",
17
+ "name": "cities",
18
+ "value": "cities-42",
19
+ "label": "London"
20
+ },
21
+ {
22
+ "id": "sunderland",
23
+ "name": "cities",
24
+ "value": "cities-56",
25
+ "label": "Sunderland"
26
+ },
27
+ {
28
+ "id": "penzance",
29
+ "name": "cities",
30
+ "value": "cities-09",
31
+ "label": "Penzance"
32
+ }
33
+ ],
34
+ "total": 5,
35
+ "skip": 0,
36
+ "limit": 10
37
+ }
@@ -0,0 +1,55 @@
1
+ {
2
+ "data": [
3
+ {
4
+ "id": "uk",
5
+ "name": "countries",
6
+ "value": "countries-12",
7
+ "label": "United Kingdom"
8
+ },
9
+ {
10
+ "id": "france",
11
+ "name": "countries",
12
+ "value": "countries-23",
13
+ "label": "France"
14
+ },
15
+ {
16
+ "id": "spain",
17
+ "name": "countries",
18
+ "value": "countries-42",
19
+ "label": "Spain"
20
+ },
21
+ {
22
+ "id": "italy",
23
+ "name": "countries",
24
+ "value": "countries-56",
25
+ "label": "Italy"
26
+ },
27
+ {
28
+ "id": "greece",
29
+ "name": "countries",
30
+ "value": "countries-09",
31
+ "label": "Greece"
32
+ },
33
+ {
34
+ "id": "turkey",
35
+ "name": "countries",
36
+ "value": "countries-13",
37
+ "label": "Turkey"
38
+ },
39
+ {
40
+ "id": "germany",
41
+ "name": "countries",
42
+ "value": "countries-76",
43
+ "label": "Germany"
44
+ },
45
+ {
46
+ "id": "portugal",
47
+ "name": "countries",
48
+ "value": "countries-34",
49
+ "label": "Portugal"
50
+ }
51
+ ],
52
+ "total": 5,
53
+ "skip": 0,
54
+ "limit": 10
55
+ }