@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,91 @@
1
+ <template>
2
+ <flex-row @click="touch()">
3
+ <flex-cell vcenter shrink>
4
+ <ux-checkbox :value="model" @click="model = !model" />
5
+ </flex-cell>
6
+ <flex-spacer />
7
+ <flex-cell vcenter>
8
+ <div>
9
+ <label class="ux-field-title" v-if="showLabel">
10
+ {{label}} <span class="ux-required-marker" v-if="required">*</span>
11
+ </label>
12
+ <div class="ux-field-description" v-if="showDescription">{{description}}</div>
13
+ </div>
14
+ </flex-cell>
15
+ </flex-row>
16
+ </template>
17
+ <script>
18
+ import NativeCheckbox from '../../ui/checkbox.vue';
19
+ import InputMixin from './input-mixin';
20
+
21
+ export default {
22
+ computed: {
23
+ NativeCheckbox,
24
+ },
25
+ mixins: [InputMixin],
26
+ props: {
27
+ modelValue: {
28
+ type: Boolean,
29
+ default () {
30
+ return false;
31
+ },
32
+ },
33
+ },
34
+ data() {
35
+ return {
36
+ value: this.modelValue,
37
+ }
38
+ },
39
+ watch: {
40
+ modelValue(val, old) {
41
+ this.value = val;
42
+ this.model = val;
43
+
44
+ }
45
+ },
46
+ computed: {
47
+ longDescription() {
48
+ return String(this.description).length > 2;
49
+ },
50
+ defaultValue() {
51
+ return false;
52
+ },
53
+ model: {
54
+ get() {
55
+ return !!this.value;
56
+ },
57
+ set(value) {
58
+ this.value = !!value;
59
+ this.$emit('update:modelValue', this.value);
60
+ }
61
+ }
62
+ }
63
+ }
64
+ </script>
65
+ <style lang="scss" scoped>
66
+ .ux-checkbox {
67
+ margin-right: 0.5em;
68
+ line-height: 1;
69
+ height: 1.5em;
70
+ width: 1.5em;
71
+ padding: 0;
72
+
73
+ &:hover {
74
+ border-color: $primary;
75
+ }
76
+
77
+ &.ux-checkbox-true {
78
+ background: $primary;
79
+ border-color: $primary;
80
+ color: #fff;
81
+ }
82
+ }
83
+
84
+ .ux-field-title {
85
+ margin: 0 !important;
86
+ }
87
+
88
+ .ux-field-description-long {
89
+ margin-top: 0.5em;
90
+ }
91
+ </style>
@@ -0,0 +1,187 @@
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
+ <template v-if="multiValue">
5
+ <div class="items" v-if="model && model.length">
6
+ <item :key="item._id" :item="item" v-for="(item, index) in model">
7
+ <template #actions>
8
+ <ux-button icon @click="remove(item)">
9
+ <ux-icon icon="fa-times" />
10
+ </ux-button>
11
+ </template>
12
+ </item>
13
+ </div>
14
+ </template>
15
+ <template v-else-if="model">
16
+ <div class="items">
17
+ <item :item="model">
18
+ <template #actions>
19
+ <ux-button icon @click="clear">
20
+ <ux-icon icon="fa-times" />
21
+ </ux-button>
22
+ </template>
23
+ </item>
24
+ </div>
25
+ </template>
26
+ <ux-button @click="open">{{summary}}</ux-button>
27
+ </template>
28
+ <script>
29
+ import Item from '../../content/item.vue';
30
+ import InputMixin from './input-mixin';
31
+
32
+ export default {
33
+ components: {
34
+ Item,
35
+ },
36
+ props: {
37
+ modelValue: {
38
+ type: [Object, Array],
39
+ },
40
+ },
41
+ mixins: [InputMixin],
42
+ created() {
43
+ this.value = this.cleanInput(this.value, true);
44
+ this.dispatch();
45
+ },
46
+ methods: {
47
+ clear() {
48
+ this.model = undefined;
49
+ this.touch();
50
+ },
51
+ // remove(index) {
52
+ // if (this.maximum == 1) {
53
+ // this.model = null
54
+ // } else {
55
+ // this.model.splice(index, 1);
56
+ // }
57
+ // },
58
+ open() {
59
+ var self = this;
60
+ self.touch();
61
+
62
+ self.$qik.browse(this.field.referenceType, {
63
+ field:self.field,
64
+ model: self.multiValue ? self.value : [self.value].filter(Boolean),
65
+ maximum: self.field.maximum,
66
+ })
67
+ .then(function(newSelection) {
68
+ self.model = self.multiValue ? newSelection : newSelection[0];
69
+ })
70
+ .catch(function(err) {
71
+ console.log('Error', err);
72
+ })
73
+ },
74
+ cleanInput(val) {
75
+
76
+ var self = this;
77
+ if (self.multiValue) {
78
+ if (!val) {
79
+ val = [];
80
+ }
81
+
82
+ if (!Array.isArray(val)) {
83
+ val = [];
84
+ }
85
+
86
+ /////////////////////////////////
87
+
88
+ if (self.maximum) {
89
+ if (val.length > self.maximum) {
90
+ val.length = self.maximum;
91
+ }
92
+ }
93
+ } else {
94
+ if (Array.isArray(val)) {
95
+ val = val[0]
96
+ }
97
+ }
98
+
99
+ return val;
100
+ },
101
+ },
102
+ computed: {
103
+ summary() {
104
+ if (this.multiValue) {
105
+ if (this.model && this.model.length) {
106
+
107
+ var length = this.model.length;
108
+
109
+
110
+ var difference = Math.max(length - 3, 0);
111
+
112
+ var summary;
113
+ var cropped = this.model.slice(0, 3);
114
+ summary = cropped.map(function(item) {
115
+ return item.firstName || item.name || item.title;
116
+ }).join(', ');
117
+
118
+ if (difference) {
119
+ summary = `${summary}... +${difference} more...`
120
+ }
121
+
122
+ return summary;
123
+
124
+ } else {
125
+ return `Click to select`;
126
+ }
127
+ } else {
128
+ if (this.model) {
129
+ return 'Click to select';
130
+ } else {
131
+ return `Click to select`;
132
+ }
133
+ }
134
+ },
135
+ }
136
+ }
137
+ </script>
138
+ <style lang="scss" scoped>
139
+ .ux-text-row {
140
+ margin-bottom: 0.5em;
141
+ }
142
+
143
+ input {
144
+ border-radius: 0.1em;
145
+ padding: 0.5em;
146
+ box-sizing: border-box;
147
+ background: rgba(#000, 0.05);
148
+ border: 1px solid rgba(#000, 0.1);
149
+ font-size: inherit;
150
+ appearance: none;
151
+ line-height: 1;
152
+ height: 2.5em;
153
+
154
+ &:focus {
155
+ background: none;
156
+ border: 1px solid $primary;
157
+ outline: none;
158
+ }
159
+ }
160
+
161
+ .ux-text-row .ux-btn {
162
+ margin-left: 0.25em;
163
+ }
164
+
165
+ .ux-text-input-multiple {
166
+ width: 100%;
167
+ }
168
+
169
+ .ux-text-input-single {
170
+ width: calc(100% - 0.5em);
171
+ margin: 0 0.5em 0 0;
172
+ }
173
+
174
+ .items {
175
+ border: 1px solid rgba(#000, 0.1);
176
+ border-radius: 0.3em;
177
+ overflow: hidden;
178
+ margin-bottom: 0.5em;
179
+
180
+ .content-item {
181
+
182
+ border: none;
183
+ border-bottom: 1px solid rgba(#000, 0.1);
184
+
185
+ }
186
+ }
187
+ </style>
@@ -0,0 +1,205 @@
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
+ <div class="ux-text-wrap" :class="{prefixed:prefix, suffixed:suffix}">
8
+ <span class="ux-text-prefix" v-if="prefix">{{prefix}}</span>
9
+ <input class="ux-field-focus ux-text-input-multiple" ref="input" placeholder="0.00" :key="`proxy-index-${index}`" @keydown.enter.stop.prevent="add()" @blur="update($event, index)" v-model.lazy="proxy[index]" @focus="touch" />
10
+ <span class="ux-text-suffix" v-if="suffix">{{suffix}}</span>
11
+ </div>
12
+ </flex-cell>
13
+ <flex-cell shrink vcenter>
14
+ <ux-button tag="a" icon v-if="canRemoveValue" @click="remove(entry)">
15
+ <ux-icon icon="fa-times" />
16
+ </ux-button>
17
+ </flex-cell>
18
+ </flex-row>
19
+ <ux-button v-if="canAddValue" @click="add()">{{addLabel}} <ux-icon icon="fa-plus" right/></ux-button>
20
+ </div>
21
+ <template v-else>
22
+ <div class="ux-text-wrap" :class="{prefixed:prefix, suffixed:suffix}">
23
+ <span class="ux-text-prefix" v-if="prefix">{{prefix}}</span>
24
+ <input class="ux-field-focus ux-text-input-single" ref="input" :key="proxy" placeholder="0.00" @keyup.enter.stop.prevent="unfocus" @focus="touch" v-model.lazy="proxy" />
25
+ <span class="ux-text-suffix" v-if="suffix">{{suffix}}</span>
26
+ </div>
27
+ </template>
28
+ </template>
29
+ <script>
30
+ import InputMixin from './input-mixin';
31
+
32
+ function setFormat(value) {
33
+ if (value != "") {
34
+ value = parseFloat(value.replace(/\//g, ""))
35
+ .toString()
36
+ .replace(/\B(?=(\d{3})+(?!\d))/g, "/");
37
+ }
38
+
39
+ return value;
40
+ }
41
+
42
+
43
+ export default {
44
+
45
+ props: {
46
+ modelValue: {
47
+ type: [String, Array],
48
+ },
49
+ },
50
+ mixins: [InputMixin],
51
+ methods: {
52
+ update(event, index) {
53
+ var formatted = this.format(event.target.value);
54
+ this.model[index] = formatted;
55
+ },
56
+ format(v) {
57
+ v = String(v).replace(/[^0-9.-]/g, '')
58
+
59
+ var v = (parseFloat(v) * 100);
60
+ if (isNaN(v)) {
61
+ return '';
62
+ }
63
+
64
+ v = Math.round(v);
65
+ return v;
66
+ },
67
+ unformat(v) {
68
+ v = String(v).replace(/[^0-9.-]/g, '')
69
+
70
+ var v = (parseFloat(v) / 100);
71
+ if (isNaN(v)) {
72
+ return '';
73
+ }
74
+
75
+ v = v.toFixed(2);
76
+ return v;
77
+ },
78
+ getNewDefaultEntry() {
79
+ return '';
80
+ },
81
+ unfocus() {
82
+ this.$refs.input.blur();
83
+ this.touch();
84
+ // this.proxy = this.proxy;
85
+ // this.model = this.format(this.unformat(this.model));
86
+ },
87
+ },
88
+ computed: {
89
+ model: {
90
+ get() {
91
+ return this.cleanOutput(this.value);
92
+ },
93
+ set(val) {
94
+ console.log('SET MODEL', val);
95
+ this.value = this.cleanInput(val);
96
+ this.dispatch();
97
+ }
98
+ },
99
+ proxy: {
100
+ get() {
101
+
102
+ var self = this;
103
+
104
+ if (self.multiValue) {
105
+ return self.model.map(self.unformat);
106
+ } else {
107
+ return self.unformat(self.model);
108
+ }
109
+ },
110
+ set(v) {
111
+ var self = this;
112
+ if (self.multiValue) {
113
+ self.model = v.map(self.format);
114
+ } else {
115
+ self.model = self.format(v);
116
+ }
117
+ }
118
+ },
119
+ currency() {
120
+ return String(this.field.currency || 'usd').toLowerCase();
121
+ },
122
+ prefix() {
123
+ return this.$qik.utils.currencySymbol(this.currency);
124
+ },
125
+ suffix() {
126
+ return String(this.currency).toUpperCase();
127
+ }
128
+ },
129
+ }
130
+ </script>
131
+ <style lang="scss" scoped>
132
+ .ux-text-row {
133
+ margin-bottom: 0.5em;
134
+ }
135
+
136
+ input {
137
+ border-radius: 0.1em;
138
+ padding: 0.5em;
139
+ box-sizing: border-box;
140
+ background: rgba(#000, 0.05);
141
+ border: 1px solid rgba(#000, 0.1);
142
+ font-size: inherit;
143
+ appearance: none;
144
+ line-height: 1;
145
+ height: 2.5em;
146
+ text-align: left;
147
+ direction: ltr;
148
+
149
+ &:focus {
150
+ background: none;
151
+ border: 1px solid $primary;
152
+ outline: none;
153
+ }
154
+ }
155
+
156
+ .ux-text-wrap {
157
+ position: relative;
158
+
159
+ &.prefixed {
160
+ input {
161
+ padding-left: 1.2em;
162
+ }
163
+ }
164
+
165
+ .ux-text-prefix {
166
+ position: absolute;
167
+ left: 0;
168
+ top: 0;
169
+ bottom: 0;
170
+ width: 1em;
171
+ pointer-events: none;
172
+ display: flex;
173
+ align-items: center;
174
+ padding: 0.5em 0;
175
+ justify-content: right;
176
+ opacity: 0.5;
177
+ }
178
+
179
+ .ux-text-suffix {
180
+ position: absolute;
181
+ top: 0;
182
+ bottom: 0;
183
+ right: 0;
184
+ pointer-events: none;
185
+ display: flex;
186
+ align-items: center;
187
+ padding: 0.5em;
188
+ opacity: 0.5;
189
+ }
190
+ }
191
+
192
+ .ux-text-row .ux-btn {
193
+ margin-left: 0.25em;
194
+ }
195
+
196
+ .ux-text-input-multiple {
197
+ width: 100%;
198
+ }
199
+
200
+ .ux-text-input-single {
201
+ width:100%;
202
+ // width: calc(100% - 0.5em);
203
+ // margin: 0 0.5em 0 0;
204
+ }
205
+ </style>
@@ -0,0 +1,132 @@
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
+ <input type="datetime-local" class="ux-field-focus ux-text-input-multiple" @focus="touch" ref="input" @keydown.enter.stop.prevent="add()" v-model="model[index]" />
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-button>
16
+ </div>
17
+ <template v-else>
18
+ <input type="datetime-local" class="ux-field-focus ux-text-input-single" @focus="touch" v-model="model" />
19
+ </template>
20
+ </template>
21
+ <script>
22
+ import InputMixin from './input-mixin';
23
+
24
+
25
+
26
+
27
+ //////////////////////////
28
+
29
+ function zero(input) {
30
+ if (String(input).length < 2) {
31
+ input = `0${input}`;
32
+ }
33
+ return input
34
+ }
35
+
36
+ //////////////////////////
37
+
38
+ export default {
39
+ props: {
40
+ modelValue: {
41
+ type: [Date, String, Array],
42
+ },
43
+ },
44
+ mixins: [InputMixin],
45
+ computed: {
46
+ model: {
47
+ get() {
48
+ let val = this.cleanOutput(this.value);
49
+ return val;
50
+ },
51
+ set(newValue) {
52
+ if (!newValue) {
53
+ this.value = undefined;
54
+ this.dispatch()
55
+ return;
56
+ }
57
+
58
+ //Invalid date so no change here
59
+ if (newValue === 'invalid') {
60
+ return;
61
+ }
62
+
63
+ ////////////////////////
64
+
65
+ var val = this.cleanOutput(newValue);
66
+ var existing = this.cleanOutput(this.value);
67
+
68
+ if (val != existing) {
69
+ newValue = this.cleanInput(val);
70
+ this.value = newValue;
71
+ this.dispatch();
72
+ }
73
+
74
+ }
75
+ },
76
+ },
77
+ methods: {
78
+ cleanOutputValue(d) {
79
+ d = d ? new Date(d) : new Date();
80
+ return `${d.getFullYear()}-${zero(d.getMonth() + 1)}-${zero(d.getDate())}T${zero(d.getHours())}:${zero(d.getMinutes())}`;
81
+ },
82
+ cleanInputValue(d) {
83
+ let dt = new Date(d);
84
+ if (dt.toString() == 'Invalid Date') {
85
+ return 'invalid';
86
+ }
87
+ return dt.toISOString();
88
+ },
89
+ getNewDefaultEntry() {
90
+ return new Date();
91
+ },
92
+ },
93
+ }
94
+ </script>
95
+ <style lang="scss" scoped>
96
+ .ux-text-row {
97
+ margin-bottom: 0.5em;
98
+ }
99
+
100
+ input {
101
+ border-radius: 0.1em;
102
+ padding: 0.5em;
103
+ box-sizing: border-box;
104
+ background: rgba(#000, 0.05);
105
+ border: 1px solid rgba(#000, 0.1);
106
+ font-size: inherit;
107
+ // appearance: none;
108
+ font-family:inherit;
109
+ line-height: 1;
110
+ height: 2.5em;
111
+
112
+ &:focus {
113
+ background: none;
114
+ border: 1px solid $primary;
115
+ outline: none;
116
+ }
117
+ }
118
+
119
+ .ux-text-row .ux-btn {
120
+ margin-left: 0.25em;
121
+ }
122
+
123
+ .ux-text-input-multiple {
124
+ width: 100%;
125
+ }
126
+
127
+ .ux-text-input-single {
128
+ width:100%;
129
+ // width: calc(100% - 0.5em);
130
+ // margin: 0 0.5em 0 0;
131
+ }
132
+ </style>