@qikdev/vue-ui 0.0.1 → 0.0.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 (72) hide show
  1. package/package.json +6 -2
  2. package/src/components.js +209 -6
  3. package/src/content/browser.vue +477 -0
  4. package/src/content/item.vue +48 -0
  5. package/src/content/render/field.vue +423 -0
  6. package/src/content/render/group.vue +65 -0
  7. package/src/content/render/render-mixin.js +101 -0
  8. package/src/content/render/render.vue +86 -0
  9. package/src/filter/FilterBuilder.vue +147 -0
  10. package/src/filter/FilterCondition.vue +335 -0
  11. package/src/filter/FilterRule.vue +257 -0
  12. package/src/form/expressions/index.js +83 -0
  13. package/src/form/field.vue +624 -0
  14. package/src/form/form.vue +280 -0
  15. package/src/form/getDefaultValue.js +224 -0
  16. package/src/form/inputs/button-select.vue +208 -0
  17. package/src/form/inputs/checkbox.vue +91 -0
  18. package/src/form/inputs/content-select.vue +187 -0
  19. package/src/form/inputs/currency.vue +205 -0
  20. package/src/form/inputs/datefield.vue +132 -0
  21. package/src/form/inputs/group.vue +155 -0
  22. package/src/form/inputs/input-mixin.js +440 -0
  23. package/src/form/inputs/native-select-old.vue +43 -0
  24. package/src/form/inputs/object-field.vue +50 -0
  25. package/src/form/inputs/option.vue +19 -0
  26. package/src/form/inputs/options-manager.vue +244 -0
  27. package/src/form/inputs/phone-number-input.vue +235 -0
  28. package/src/form/inputs/search.vue +117 -0
  29. package/src/form/inputs/select.vue +211 -0
  30. package/src/form/inputs/switch.vue +87 -0
  31. package/src/form/inputs/textarea.vue +80 -0
  32. package/src/form/inputs/textfield.vue +165 -0
  33. package/src/form/inputs/timezone.vue +642 -0
  34. package/src/form/inputs/upload/filedrop.vue +72 -0
  35. package/src/form/inputs/upload/upload.vue +323 -0
  36. package/src/form/parseBoolean.js +24 -0
  37. package/src/layout/flex-body.vue +3 -2
  38. package/src/layout/flex-cell.vue +45 -0
  39. package/src/layout/flex-column.vue +1 -1
  40. package/src/layout/flex-footer.vue +3 -2
  41. package/src/layout/flex-header.vue +3 -2
  42. package/src/layout/flex-row.vue +35 -0
  43. package/src/layout/flex-spacer.vue +17 -0
  44. package/src/layout/panel-body.vue +13 -0
  45. package/src/layout/panel-footer.vue +20 -0
  46. package/src/layout/panel-header.vue +20 -0
  47. package/src/layout/panel.vue +23 -0
  48. package/src/modal/ConfirmModal.vue +50 -0
  49. package/src/modal/ContentModal.vue +99 -0
  50. package/src/modal/Modal.vue +85 -0
  51. package/src/modal/ModalMixin.js +21 -0
  52. package/src/modal/OptionsModal.vue +31 -0
  53. package/src/modal/PromptModal.vue +31 -0
  54. package/src/services/selection.js +140 -0
  55. package/src/table/Table.vue +269 -0
  56. package/src/table/TableCell.vue +64 -0
  57. package/src/table/TableRow.vue +94 -0
  58. package/src/table/cells/TableCellMixin.js +15 -0
  59. package/src/table/cells/Thumbnail.vue +38 -0
  60. package/src/ui/button.vue +254 -0
  61. package/src/ui/checkbox.vue +79 -0
  62. package/src/ui/icon.vue +57 -0
  63. package/src/ui/image.vue +158 -0
  64. package/src/ui/link.vue +62 -0
  65. package/src/ui/list-item.vue +16 -0
  66. package/src/ui/list.vue +26 -0
  67. package/src/ui/menu.vue +135 -0
  68. package/src/ui/progressbar.vue +77 -0
  69. package/src/ui/spinner.vue +26 -0
  70. package/src/ui/switch.vue +89 -0
  71. package/yarn-error.log +2923 -0
  72. package/index.js +0 -14
@@ -0,0 +1,155 @@
1
+ <template>
2
+
3
+ <div class="ux-multi-group" v-if="multiValue">
4
+ <panel ref="row" :key="entry" v-for="(entry, index) in model">
5
+ <panel-header>
6
+ <flex-row>
7
+ <flex-cell vcenter>
8
+ <div>
9
+ <strong>{{multiLabel(entry, index)}}</strong>
10
+ </div>
11
+ </flex-cell>
12
+ <flex-cell vcenter shrink>
13
+ <ux-button icon tag="a" v-if="canRemoveValue" @click="remove(entry)">
14
+ <ux-icon icon="fa-times" />
15
+ </ux-button>
16
+ </flex-cell>
17
+ </flex-row>
18
+ </panel-header>
19
+ <panel-body @keydown.enter="enterPress($event)">
20
+ <ux-form ref="form" @form:state="stateChange" :parentModel="parentModel" v-model="model[index]" :flex="sameLine" :fields="field.fields" />
21
+ </panel-body>
22
+ </panel>
23
+ <ux-button v-if="canAddValue" @click="add()">{{addLabel}}
24
+ <ux-icon icon="fa-plus" right />
25
+ </ux-button>
26
+ </div>
27
+ <template v-else>
28
+ <ux-form ref="form" @form:state="stateChange" :parentModel="parentModel" v-model="model" :flex="sameLine" :fields="field.fields" />
29
+ </template>
30
+
31
+ <!-- <pre><strong>{{field.title}}</strong>
32
+
33
+ Should be single: {{singleValue}}, {{asObject}}, {{minimum == 1}} {{maximum == 1}}
34
+ Multi: {{multiValue}};
35
+ Can Add Value: {{canAddValue}}
36
+ Number Values: {{numValues}}
37
+ Model: {{model}}
38
+ </pre> -->
39
+ </template>
40
+ <script>
41
+ import InputMixin from './input-mixin';
42
+
43
+
44
+ export default {
45
+ mixins: [InputMixin],
46
+ props: {
47
+ modelValue: {
48
+ type: [Object, Array],
49
+ },
50
+ },
51
+ // created() {
52
+ // // this.value = this.cleanInput(this.value, true);
53
+ // },
54
+ computed: {
55
+ sameLine() {
56
+ return this.field.sameLine;
57
+ }
58
+ },
59
+ methods: {
60
+ stateChange(details) {
61
+ this.$emit('form:state', details);
62
+ },
63
+ multiLabel(entry, index) {
64
+
65
+ if (entry.name) {
66
+ return entry.name;
67
+ }
68
+
69
+ if (entry.title) {
70
+ return entry.title;
71
+ }
72
+
73
+ if (entry.firstName) {
74
+ return entry.firstName;
75
+ }
76
+
77
+ return `${this.label} ${index+1}`
78
+ },
79
+ getNewDefaultEntry() {
80
+ return {};
81
+ },
82
+ enterPress(event) {
83
+ if (this.canAddValue) {
84
+ event.stopImmediatePropagation();
85
+ event.preventDefault();
86
+ this.add();
87
+ }
88
+ },
89
+ refocus() {
90
+ this.$nextTick(function() {
91
+
92
+ //Find the last row
93
+ var rows = this.$refs.row;
94
+ var lastRow = rows[rows.length - 1];
95
+
96
+ if (!lastRow) {
97
+ return;
98
+ }
99
+ var input = lastRow.$el.querySelector('.ux-field-focus');
100
+
101
+ if (!input) {
102
+ return;
103
+ }
104
+ input.focus();
105
+ })
106
+ },
107
+ getNewDefaultEntry() {
108
+ return {};
109
+ },
110
+ // cleanInput(model) {
111
+
112
+ // var self = this;
113
+ // var setDefaults = true;
114
+
115
+ // if (self.multiValue) {
116
+ // if (!model) {
117
+ // model = [];
118
+ // }
119
+
120
+ // if (!Array.isArray(model)) {
121
+ // model = [model];
122
+ // }
123
+
124
+ // /////////////////////////////////
125
+
126
+ // if (self.maximum) {
127
+ // if (model.length > self.maximum) {
128
+ // model.length = self.maximum;
129
+ // }
130
+ // }
131
+
132
+ // var min = setDefaults ? self.ask : self.minimum;
133
+ // while (model.length < min) {
134
+ // model.push(self.getNewDefaultEntry())
135
+ // }
136
+
137
+ // } else {
138
+ // if (!model) {
139
+ // model = self.getNewDefaultEntry();
140
+ // }
141
+ // }
142
+
143
+ // ///////////////////////////
144
+
145
+
146
+ // return model;
147
+ // }
148
+ }
149
+ }
150
+ </script>
151
+ <style lang="scss" scoped>
152
+ .ux-multi-group {
153
+ margin-bottom: 1em;
154
+ }
155
+ </style>
@@ -0,0 +1,440 @@
1
+ function isUndefined(v, type) {
2
+ return v === undefined ||
3
+ v === null || (type == 'date' && v.toString && (v.toString() === 'Invalid Date'));
4
+ }
5
+
6
+
7
+
8
+
9
+
10
+ export default {
11
+ props: {
12
+ field: {
13
+ type: Object,
14
+ default () {
15
+ return {}
16
+ },
17
+ },
18
+ parentModel: {
19
+ type: Object,
20
+ },
21
+ },
22
+ data() {
23
+ return {
24
+ value: this.modelValue,
25
+ }
26
+ },
27
+ watch: {
28
+ modelValue(val, old) {
29
+
30
+ var cleanedValue = this.cleanInput(val);
31
+ var cleanedModel = this.cleanInput(this.model);
32
+
33
+ if (JSON.stringify(cleanedValue) != JSON.stringify(cleanedModel)) {
34
+ this.model = cleanedValue
35
+ }
36
+
37
+ },
38
+ },
39
+ mounted() {
40
+ this.checkAutofocus();
41
+ },
42
+ computed: {
43
+ optionLookup() {
44
+ var self = this;
45
+ return self.options.reduce(function(set, option) {
46
+ const key = self.getValue(option);
47
+ set[key] = option;
48
+ return set;
49
+ }, {})
50
+ },
51
+ selectableOptions() {
52
+ return this.options;
53
+ },
54
+ required() {
55
+ return this.minimum;
56
+ },
57
+ model: {
58
+ get() {
59
+ return this.cleanOutput(this.value);
60
+ },
61
+ set(val) {
62
+ this.value = this.cleanInput(val);
63
+
64
+ this.checkAutofocus();
65
+ this.dispatch();
66
+ }
67
+ },
68
+ options() {
69
+ var self = this;
70
+ return (this.field.options || []).reduce(function(set, option) {
71
+ if (!option) {
72
+ return set;
73
+ }
74
+ const value = self.getValue(option);
75
+ const title = option.title || option.name || option.label || value;
76
+
77
+
78
+ var output = {
79
+ title,
80
+ value,
81
+ source: option,
82
+ }
83
+
84
+ if (self.field.type == 'reference') {
85
+ output._id = value;
86
+ }
87
+
88
+ set.push(output);
89
+
90
+ return set;
91
+ }, [])
92
+ },
93
+ prefix() {
94
+ return this.field.suffix;
95
+ },
96
+ suffix() {
97
+ return this.field.suffix;
98
+ },
99
+ type() {
100
+ if (!this.field) {
101
+ console.log('TYPE', this.field)
102
+ }
103
+ return this.field.type || 'string';
104
+ },
105
+ key() {
106
+ return this.field.key;
107
+ },
108
+ isGroup() {
109
+ return this.type === 'group'
110
+ },
111
+ asObject() {
112
+ return this.isGroup && !!this.field.asObject;
113
+ },
114
+ layoutGroup() {
115
+ return this.isGroup && !this.field.asObject;
116
+ },
117
+ canAddValue() {
118
+
119
+ if (this.singleValue) {
120
+ return;
121
+ }
122
+
123
+ return this.maximum === 0 || this.numValues < this.maximum;
124
+ },
125
+ canRemoveValue() {
126
+ return this.numValues > this.minimum;
127
+ },
128
+ singleValue() {
129
+ if (this.asObject) {
130
+ var isSingle = this.minimum === 1 && this.maximum === 1;
131
+ return isSingle;
132
+ } else {
133
+ return this.maximum === 1;
134
+ }
135
+ },
136
+ multiValue() {
137
+ return !this.singleValue;
138
+ },
139
+ label() {
140
+ return this.field.title;
141
+ },
142
+ description() {
143
+ return this.field.description;
144
+ },
145
+ placeholder() {
146
+ return this.field.placeholder || this.field.hint;
147
+ },
148
+ addLabel() {
149
+ if (this.numValues) {
150
+ return `Add another ${this.label}`
151
+
152
+ } else {
153
+ return `Add ${this.label}`
154
+ }
155
+ },
156
+ removeLabel() {
157
+ return `Remove`
158
+ },
159
+ numValues() {
160
+ if (this.singleValue) {
161
+ return 1;
162
+ }
163
+ return (this.value || []).length || 0;
164
+ },
165
+
166
+ showLabel() {
167
+ return this.field.title;
168
+ },
169
+ showDescription() {
170
+ return this.description;
171
+ },
172
+ fields() {
173
+ var subFields = this.field.fields;
174
+
175
+ if (subFields && subFields.length) {
176
+ return subFields;
177
+ }
178
+ },
179
+ minimum() {
180
+ if (this.layoutGroup) {
181
+ return 1;
182
+ }
183
+
184
+ var int = parseInt(this.field.minimum || 0);
185
+ if (isNaN(int)) {
186
+ int = 0;
187
+ }
188
+
189
+ int = Math.max(int, 0)
190
+ int = this.maximum ? Math.min(int, this.maximum) : int;
191
+ return parseInt(int);
192
+ },
193
+ maximum() {
194
+ if (this.layoutGroup) {
195
+ return 1;
196
+ }
197
+
198
+ var int = parseInt(this.field.maximum || 0);
199
+ if (isNaN(int)) {
200
+ int = 0;
201
+ }
202
+ int = Math.max(int, 0)
203
+ return parseInt(int);
204
+ },
205
+ ask() {
206
+ var int = parseInt(this.field.ask);
207
+ int = Math.max(int, this.minimum);
208
+ if (this.maximum) {
209
+ int = Math.min(int, this.maximum);
210
+ }
211
+
212
+ return int;
213
+ },
214
+ },
215
+ methods: {
216
+ cleanTextInput(val, type, instance) {
217
+ switch (type) {
218
+ case 'url':
219
+ val = instance.$qik.utils.parseURL(val);
220
+ break;
221
+ case 'key':
222
+ val = instance.$qik.utils.machineName(val);
223
+ break;
224
+ case 'integer':
225
+ val = parseInt(String(val).replace(/[^0-9-]/g, ''));
226
+ if (isNaN(val)) {
227
+ val = undefined;
228
+ }
229
+ break;
230
+ case 'number':
231
+ case 'decimal':
232
+ case 'float':
233
+ val = Number(String(val).replace(/[^0-9.-]/g, ''));
234
+ if (isNaN(val)) {
235
+ val = undefined;
236
+ }
237
+ break;
238
+ }
239
+ return val;
240
+ },
241
+ checkAutofocus() {
242
+ if (this.field.autofocus) {
243
+
244
+ if (this.value) {
245
+ return;
246
+ }
247
+
248
+ this.$nextTick(function() {
249
+
250
+
251
+ this.refocus();
252
+ })
253
+ }
254
+ },
255
+ getValue(option) {
256
+ if (!option) {
257
+ return;
258
+ }
259
+
260
+ //Get the value of the object
261
+ var value = option._id || option.value;
262
+
263
+ //If we have a title but no value
264
+ if(!value && option.title && !this.returnObject) {
265
+ //user the title as the value
266
+ value = option.title;
267
+ }
268
+
269
+ //Return the value or the option itself
270
+ return value || option;
271
+ },
272
+ getLabel(option) {
273
+ if (!option) {
274
+ return;
275
+ }
276
+
277
+ var label = option.title || option.name || option.label;
278
+
279
+ if(typeof label == 'object') {
280
+ return '(no title)'
281
+ } else {
282
+ return label
283
+ }
284
+ },
285
+ touch() {
286
+ this.$emit('touched');
287
+ },
288
+ getNewDefaultEntry() {
289
+ return undefined;
290
+ },
291
+ add() {
292
+ if (!this.canAddValue) {
293
+ return;
294
+ }
295
+
296
+ var defaultEntry = this.cleanInputValue(this.getNewDefaultEntry());
297
+
298
+ if (!this.value || !Array.isArray(this.value)) {
299
+ this.value = []
300
+ }
301
+
302
+ this.value.push(defaultEntry);
303
+ this.dispatch();
304
+
305
+ this.$nextTick(function() {
306
+ this.refocus()
307
+ })
308
+
309
+ this.touch();
310
+ },
311
+ remove(entry) {
312
+ var index = this.model.indexOf(entry);
313
+ this.value.splice(index, 1);
314
+ this.dispatch();
315
+ this.touch();
316
+ },
317
+ dispatch() {
318
+ this.$emit('update:modelValue', this.value);
319
+ },
320
+
321
+ cleanInputValue(val) {
322
+ // if (!isUndefined(val, this.type)) {
323
+ // switch (this.type) {
324
+ // case 'integer':
325
+ // val = parseInt(val);
326
+ // break;
327
+ // case 'float':
328
+ // case 'decimal':
329
+ // case 'number':
330
+ // val = Number(val);
331
+ // break;
332
+ // }
333
+ // }
334
+
335
+ return val;
336
+ },
337
+ cleanOutputValue(val) {
338
+ return val;
339
+ },
340
+ cleanOutput(val) {
341
+
342
+ var self = this;
343
+
344
+
345
+
346
+
347
+ if (isUndefined(val, self.field.type)) {
348
+ if (self.multiValue) {
349
+ val = [];
350
+ } else {
351
+ val = undefined;
352
+ }
353
+ } else {
354
+ if (self.multiValue) {
355
+
356
+ if (!Array.isArray(val)) {
357
+ val = []
358
+ }
359
+
360
+ val.forEach(function(v, i) {
361
+ val[i] = self.cleanOutputValue(v);
362
+ });
363
+ // val = val.map(function(i) {
364
+ // return self.cleanOutputValue(i)
365
+ // })
366
+ } else {
367
+ val = self.cleanOutputValue(val)
368
+ }
369
+ }
370
+
371
+ return val;
372
+ },
373
+
374
+ cleanInput(val) {
375
+ var input = val;
376
+
377
+ var self = this;
378
+
379
+ if (self.multiValue) {
380
+ if (!val) {
381
+ val = [];
382
+ }
383
+
384
+ if (!Array.isArray(val)) {
385
+ val = [val];
386
+ }
387
+
388
+ /////////////////////////////////
389
+
390
+ if (self.maximum) {
391
+ if (val.length > self.maximum) {
392
+ val.length = self.maximum;
393
+ }
394
+ }
395
+
396
+ while (val.length < self.minimum) {
397
+ val.push(self.cleanInputValue(self.getNewDefaultEntry()));
398
+ }
399
+
400
+ val = val.map(function(v) {
401
+ var d = self.cleanInputValue(v)
402
+ // toISO(v)
403
+ return d;
404
+ })
405
+ } else {
406
+ if (val) {
407
+ // val = toISO(val)
408
+ val = self.cleanInputValue(val)
409
+ }
410
+ }
411
+
412
+
413
+ var out = val;
414
+ return val;
415
+ },
416
+
417
+
418
+
419
+ refocus() {
420
+ var elements = this.$refs.input;
421
+
422
+ if (!elements) {
423
+ return;
424
+ }
425
+
426
+
427
+ var input;
428
+ if (Array.isArray(elements)) {
429
+ input = elements[elements.length - 1];
430
+ } else {
431
+ input = elements;
432
+ }
433
+
434
+ if (input) {
435
+
436
+ input.focus();
437
+ }
438
+ },
439
+ }
440
+ }
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <div class="native-select">
3
+ <select v-model="model">
4
+ <option :value="option.value" v-for="option in selectableOptions">{{option.label}}</option>
5
+ </select>
6
+ <slot />
7
+ </div>
8
+ </template>
9
+ <script>
10
+
11
+ import InputMixin from './input-mixin';
12
+
13
+ export default {
14
+ mixins:[InputMixin],
15
+ computed: {
16
+ selectableOptions() {
17
+ return this.options.map(function(option) {
18
+ const value = option.value || option;
19
+ const label = option.title || option.name || option.label || value;
20
+
21
+ return {
22
+ label,
23
+ value,
24
+ }
25
+ })
26
+ },
27
+ }
28
+ }
29
+ </script>
30
+ <style lang="scss" scoped>
31
+ .native-select {
32
+ position: relative;
33
+
34
+
35
+ select {
36
+ opacity: 0;
37
+ appearance: none;
38
+ width: 100%;
39
+ height: 100%;
40
+ position: absolute;
41
+ }
42
+ }
43
+ </style>
@@ -0,0 +1,50 @@
1
+ <template>
2
+ <label class="ux-field-title" v-if="showLabel">{{label}} <span class="ux-required-marker" v-if="required">*</span></label>
3
+ <div class="ux-field-description" v-if="showDescription">{{description}}</div>
4
+ <div v-if="multiValue">
5
+ <flex-row class="ux-text-row" :key="index" v-for="(entry, index) in model">
6
+ <flex-cell>
7
+ <pre>{{entry}}</pre>
8
+ </flex-cell>
9
+ <flex-cell shrink vcenter>
10
+ <ux-button tag="a" icon v-if="canRemoveValue" @click="remove(entry)">
11
+ <ux-icon icon="fa-times" />
12
+ </ux-button>
13
+ </flex-cell>
14
+ </flex-row>
15
+ <ux-button v-if="canAddValue" @click="add()">{{addLabel}} <ux-icon icon="fa-plus" right/></ux-button>
16
+ </div>
17
+ <template v-else>
18
+ <pre>{{model}}</pre>
19
+ </template>
20
+ </template>
21
+ <script>
22
+ import InputMixin from './input-mixin';
23
+
24
+ export default {
25
+ props: {
26
+ modelValue: {
27
+ type:Object,
28
+ },
29
+ },
30
+ mixins: [InputMixin],
31
+ computed: {
32
+
33
+ },
34
+ methods: {
35
+ getNewDefaultEntry() {
36
+ return {};
37
+ },
38
+ },
39
+ }
40
+ </script>
41
+ <style lang="scss" scoped>
42
+ pre {
43
+ border-radius:0.5em;
44
+ background: #222;
45
+ font-size: 0.8em;
46
+ color: #ddd;
47
+ padding: 1em;
48
+ display: block;
49
+ }
50
+ </style>
@@ -0,0 +1,19 @@
1
+ <template>
2
+ <slot :plainValue="plainValue">
3
+ <pre>{{option}}</pre>
4
+ </slot>
5
+ </template>
6
+ <script>
7
+ export default {
8
+ props: {
9
+ option: {
10
+ required:true,
11
+ }
12
+ },
13
+ computed: {
14
+ plainValue() {
15
+ return this.option._id || this.option.value || this.option;
16
+ },
17
+ }
18
+ }
19
+ </script>