goodteditor-ui 1.0.12 → 1.0.13
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/.eslintrc.js +7 -7
- package/.prettierrc +14 -14
- package/README.md +35 -35
- package/babel.config.js +5 -5
- package/dist/js.png +0 -0
- package/index.js +51 -51
- package/jsconfig.json +13 -13
- package/package.json +57 -57
- package/src/App.vue +36 -36
- package/src/components/ui/Avatar.md +68 -68
- package/src/components/ui/Avatar.vue +177 -177
- package/src/components/ui/Badge.md +20 -20
- package/src/components/ui/Badge.vue +75 -75
- package/src/components/ui/Collapse.md +90 -90
- package/src/components/ui/Collapse.vue +86 -86
- package/src/components/ui/ColorPicker/Alpha.vue +114 -114
- package/src/components/ui/ColorPicker/Colors.vue +117 -117
- package/src/components/ui/ColorPicker/Hue.vue +113 -113
- package/src/components/ui/ColorPicker/Preview.vue +55 -55
- package/src/components/ui/ColorPicker/Saturation.vue +123 -123
- package/src/components/ui/ColorPicker/mixin.js +105 -105
- package/src/components/ui/ColorPicker.md +17 -17
- package/src/components/ui/ColorPicker.vue +314 -314
- package/src/components/ui/Datalist.md +41 -41
- package/src/components/ui/Datalist.vue +157 -157
- package/src/components/ui/DatePicker.md +168 -168
- package/src/components/ui/DatePicker.vue +527 -527
- package/src/components/ui/FileSelector.md +105 -105
- package/src/components/ui/FileSelector.vue +82 -82
- package/src/components/ui/Grid.md +130 -130
- package/src/components/ui/Grid.vue +92 -92
- package/src/components/ui/Image.md +59 -59
- package/src/components/ui/Image.vue +57 -57
- package/src/components/ui/InputAutocomplete.md +115 -115
- package/src/components/ui/InputAutocomplete.vue +341 -341
- package/src/components/ui/InputColorPicker.md +51 -51
- package/src/components/ui/InputColorPicker.vue +151 -151
- package/src/components/ui/InputDatePicker.md +121 -121
- package/src/components/ui/InputDatePicker.vue +310 -310
- package/src/components/ui/InputTags.md +51 -51
- package/src/components/ui/InputTags.vue +184 -184
- package/src/components/ui/InputTimePicker.md +25 -25
- package/src/components/ui/InputTimePicker.vue +253 -253
- package/src/components/ui/InputUnits.md +20 -20
- package/src/components/ui/InputUnits.vue +257 -257
- package/src/components/ui/Lazy.md +37 -37
- package/src/components/ui/Lazy.vue +92 -92
- package/src/components/ui/Pagination.md +74 -74
- package/src/components/ui/Pagination.vue +138 -138
- package/src/components/ui/Paginator.md +34 -34
- package/src/components/ui/Paginator.vue +83 -83
- package/src/components/ui/Popover.md +34 -34
- package/src/components/ui/Popover.vue +258 -209
- package/src/components/ui/Popup.md +59 -59
- package/src/components/ui/Popup.vue +150 -150
- package/src/components/ui/ResponsiveContainer.md +58 -58
- package/src/components/ui/ResponsiveContainer.vue +99 -99
- package/src/components/ui/Select.md +187 -187
- package/src/components/ui/Select.vue +420 -420
- package/src/components/ui/TimePicker.md +50 -50
- package/src/components/ui/TimePicker.vue +252 -252
- package/src/components/ui/Tooltip.md +114 -52
- package/src/components/ui/Tooltip.vue +113 -113
- package/src/components/ui/utils/FormComponent.js +107 -107
- package/src/components/ui/utils/Helpers.js +84 -61
- package/src/components/ui/utils/WithPopover.js +99 -81
- package/src/main.js +8 -8
- package/styleguide.config.js +37 -37
- package/vue.config.js +8 -8
- package/.idea/codeStyles/Project.xml +0 -51
- package/.idea/codeStyles/codeStyleConfig.xml +0 -5
- package/.idea/goodt-ui.iml +0 -12
- package/.idea/inspectionProfiles/Project_Default.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -6
|
@@ -1,92 +1,92 @@
|
|
|
1
|
-
<style lang="less" scoped>
|
|
2
|
-
.ui-grid {
|
|
3
|
-
display: grid;
|
|
4
|
-
}
|
|
5
|
-
</style>
|
|
6
|
-
<script>
|
|
7
|
-
export default {
|
|
8
|
-
props: {
|
|
9
|
-
/**
|
|
10
|
-
* Grid areas defined as a 2d array, which describe the layout (areas are mapped to slot names)
|
|
11
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-areas
|
|
12
|
-
*/
|
|
13
|
-
areas: {
|
|
14
|
-
type: Array,
|
|
15
|
-
default() {
|
|
16
|
-
return [['default']];
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
/**
|
|
20
|
-
* Grid colum sizes array
|
|
21
|
-
* @see Possible values: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns#values
|
|
22
|
-
*/
|
|
23
|
-
cols: {
|
|
24
|
-
type: Array,
|
|
25
|
-
default() {
|
|
26
|
-
return ['1fr'];
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
/**
|
|
30
|
-
* Grid row sizes array
|
|
31
|
-
* @see Possible values: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-rows#values
|
|
32
|
-
*/
|
|
33
|
-
rows: {
|
|
34
|
-
type: Array,
|
|
35
|
-
default() {
|
|
36
|
-
return ['1fr'];
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
/**
|
|
40
|
-
* Grid gaps array [<row-gap>, <column-gap>]
|
|
41
|
-
*/
|
|
42
|
-
gap: {
|
|
43
|
-
type: Array,
|
|
44
|
-
default() {
|
|
45
|
-
return [0, 0];
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
/**
|
|
49
|
-
* Wrapper element tag name @default null
|
|
50
|
-
*/
|
|
51
|
-
wrapTag: {
|
|
52
|
-
type: String,
|
|
53
|
-
default: null,
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
computed: {
|
|
57
|
-
gridStyle() {
|
|
58
|
-
const { areas, cols, rows, gap } = this;
|
|
59
|
-
const areasStr = areas.map(row => `"${row.join(' ')}"`).join(' ');
|
|
60
|
-
return {
|
|
61
|
-
'grid-template-areas': areasStr,
|
|
62
|
-
'grid-template-columns': cols.join(' '),
|
|
63
|
-
'grid-template-rows': rows.join(' '),
|
|
64
|
-
gap: gap.join(' '),
|
|
65
|
-
};
|
|
66
|
-
},
|
|
67
|
-
slotNames() {
|
|
68
|
-
const { areas } = this;
|
|
69
|
-
return [...new Set(areas.flat())].filter(val => val != '.');
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
methods: {
|
|
73
|
-
getSlotStyle(name) {
|
|
74
|
-
return { 'grid-area': name };
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
render(h) {
|
|
78
|
-
const { wrapTag, slotNames, gridStyle, getSlotStyle, $scopedSlots } = this;
|
|
79
|
-
const children = slotNames.map(name => {
|
|
80
|
-
const slot = $scopedSlots[name];
|
|
81
|
-
if (!slot) {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
const slotChild = slot({ style: getSlotStyle(name) });
|
|
85
|
-
return wrapTag
|
|
86
|
-
? h(wrapTag, { style: getSlotStyle(name), key: name }, [slotChild])
|
|
87
|
-
: slotChild;
|
|
88
|
-
});
|
|
89
|
-
return h('div', { class: 'ui-grid', style: gridStyle }, children);
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
</script>
|
|
1
|
+
<style lang="less" scoped>
|
|
2
|
+
.ui-grid {
|
|
3
|
+
display: grid;
|
|
4
|
+
}
|
|
5
|
+
</style>
|
|
6
|
+
<script>
|
|
7
|
+
export default {
|
|
8
|
+
props: {
|
|
9
|
+
/**
|
|
10
|
+
* Grid areas defined as a 2d array, which describe the layout (areas are mapped to slot names)
|
|
11
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-areas
|
|
12
|
+
*/
|
|
13
|
+
areas: {
|
|
14
|
+
type: Array,
|
|
15
|
+
default() {
|
|
16
|
+
return [['default']];
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
/**
|
|
20
|
+
* Grid colum sizes array
|
|
21
|
+
* @see Possible values: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns#values
|
|
22
|
+
*/
|
|
23
|
+
cols: {
|
|
24
|
+
type: Array,
|
|
25
|
+
default() {
|
|
26
|
+
return ['1fr'];
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
/**
|
|
30
|
+
* Grid row sizes array
|
|
31
|
+
* @see Possible values: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-rows#values
|
|
32
|
+
*/
|
|
33
|
+
rows: {
|
|
34
|
+
type: Array,
|
|
35
|
+
default() {
|
|
36
|
+
return ['1fr'];
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
/**
|
|
40
|
+
* Grid gaps array [<row-gap>, <column-gap>]
|
|
41
|
+
*/
|
|
42
|
+
gap: {
|
|
43
|
+
type: Array,
|
|
44
|
+
default() {
|
|
45
|
+
return [0, 0];
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
/**
|
|
49
|
+
* Wrapper element tag name @default null
|
|
50
|
+
*/
|
|
51
|
+
wrapTag: {
|
|
52
|
+
type: String,
|
|
53
|
+
default: null,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
computed: {
|
|
57
|
+
gridStyle() {
|
|
58
|
+
const { areas, cols, rows, gap } = this;
|
|
59
|
+
const areasStr = areas.map(row => `"${row.join(' ')}"`).join(' ');
|
|
60
|
+
return {
|
|
61
|
+
'grid-template-areas': areasStr,
|
|
62
|
+
'grid-template-columns': cols.join(' '),
|
|
63
|
+
'grid-template-rows': rows.join(' '),
|
|
64
|
+
gap: gap.join(' '),
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
slotNames() {
|
|
68
|
+
const { areas } = this;
|
|
69
|
+
return [...new Set(areas.flat())].filter(val => val != '.');
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
methods: {
|
|
73
|
+
getSlotStyle(name) {
|
|
74
|
+
return { 'grid-area': name };
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
render(h) {
|
|
78
|
+
const { wrapTag, slotNames, gridStyle, getSlotStyle, $scopedSlots } = this;
|
|
79
|
+
const children = slotNames.map(name => {
|
|
80
|
+
const slot = $scopedSlots[name];
|
|
81
|
+
if (!slot) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
const slotChild = slot({ style: getSlotStyle(name) });
|
|
85
|
+
return wrapTag
|
|
86
|
+
? h(wrapTag, { style: getSlotStyle(name), key: name }, [slotChild])
|
|
87
|
+
: slotChild;
|
|
88
|
+
});
|
|
89
|
+
return h('div', { class: 'ui-grid', style: gridStyle }, children);
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
</script>
|
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
```vue
|
|
2
|
-
<template>
|
|
3
|
-
<div class="pad-l5">
|
|
4
|
-
<div class="p">
|
|
5
|
-
<div class="row">
|
|
6
|
-
<div class="col">
|
|
7
|
-
<div>String:</div>
|
|
8
|
-
<input
|
|
9
|
-
class="input input-small w-12-12 v-top"
|
|
10
|
-
type="text"
|
|
11
|
-
v-model="props.src"
|
|
12
|
-
/>
|
|
13
|
-
</div>
|
|
14
|
-
<div class="col">
|
|
15
|
-
<div>File:</div>
|
|
16
|
-
<ui-file-selector accept="image/*" @change="onFilesChange">
|
|
17
|
-
<div class="btn btn-primary btn-small">select local image</div>
|
|
18
|
-
</ui-file-selector>
|
|
19
|
-
</div>
|
|
20
|
-
<div class="col">
|
|
21
|
-
<div>Promise:</div>
|
|
22
|
-
<div class="btn btn-primary btn-small" @click="onImportImage">
|
|
23
|
-
import() image
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
<ui-image v-bind="props" style="max-height:3rem">
|
|
29
|
-
<i class="preloader"></i>
|
|
30
|
-
</ui-image>
|
|
31
|
-
</div>
|
|
32
|
-
</template>
|
|
33
|
-
<script>
|
|
34
|
-
import UiFileSelector from './FileSelector.vue';
|
|
35
|
-
import UiImage from './Image.vue';
|
|
36
|
-
|
|
37
|
-
export default {
|
|
38
|
-
components: { UiFileSelector, UiImage },
|
|
39
|
-
data() {
|
|
40
|
-
return {
|
|
41
|
-
props: {
|
|
42
|
-
src: 'https://vuejs.org/images/logo.svg',
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
},
|
|
46
|
-
methods: {
|
|
47
|
-
onImportImage() {
|
|
48
|
-
// @NOTE async import() not working in demo previews
|
|
49
|
-
this.props.src = Promise.resolve(require('/public/js.png'));
|
|
50
|
-
},
|
|
51
|
-
onFilesChange(files) {
|
|
52
|
-
if (files.length) {
|
|
53
|
-
this.props.src = files[0];
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
</script>
|
|
59
|
-
```
|
|
1
|
+
```vue
|
|
2
|
+
<template>
|
|
3
|
+
<div class="pad-l5">
|
|
4
|
+
<div class="p">
|
|
5
|
+
<div class="row">
|
|
6
|
+
<div class="col">
|
|
7
|
+
<div>String:</div>
|
|
8
|
+
<input
|
|
9
|
+
class="input input-small w-12-12 v-top"
|
|
10
|
+
type="text"
|
|
11
|
+
v-model="props.src"
|
|
12
|
+
/>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="col">
|
|
15
|
+
<div>File:</div>
|
|
16
|
+
<ui-file-selector accept="image/*" @change="onFilesChange">
|
|
17
|
+
<div class="btn btn-primary btn-small">select local image</div>
|
|
18
|
+
</ui-file-selector>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="col">
|
|
21
|
+
<div>Promise:</div>
|
|
22
|
+
<div class="btn btn-primary btn-small" @click="onImportImage">
|
|
23
|
+
import() image
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
<ui-image v-bind="props" style="max-height:3rem">
|
|
29
|
+
<i class="preloader"></i>
|
|
30
|
+
</ui-image>
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
33
|
+
<script>
|
|
34
|
+
import UiFileSelector from './FileSelector.vue';
|
|
35
|
+
import UiImage from './Image.vue';
|
|
36
|
+
|
|
37
|
+
export default {
|
|
38
|
+
components: { UiFileSelector, UiImage },
|
|
39
|
+
data() {
|
|
40
|
+
return {
|
|
41
|
+
props: {
|
|
42
|
+
src: 'https://vuejs.org/images/logo.svg',
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
methods: {
|
|
47
|
+
onImportImage() {
|
|
48
|
+
// @NOTE async import() not working in demo previews
|
|
49
|
+
this.props.src = Promise.resolve(require('/public/js.png'));
|
|
50
|
+
},
|
|
51
|
+
onFilesChange(files) {
|
|
52
|
+
if (files.length) {
|
|
53
|
+
this.props.src = files[0];
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
</script>
|
|
59
|
+
```
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
/**
|
|
3
|
-
* @param {File} file
|
|
4
|
-
* @return {Promise<string>}
|
|
5
|
-
*/
|
|
6
|
-
const loadFile = file => {
|
|
7
|
-
return new Promise(resolve => {
|
|
8
|
-
const fr = new FileReader();
|
|
9
|
-
fr.addEventListener('load', ({ target }) => resolve(target.result));
|
|
10
|
-
fr.readAsDataURL(file);
|
|
11
|
-
});
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export default {
|
|
15
|
-
props: {
|
|
16
|
-
/**
|
|
17
|
-
* Image source (String, File, Promise<Module>, Promise<File>)
|
|
18
|
-
*/
|
|
19
|
-
src: {
|
|
20
|
-
type: [String, File, Promise],
|
|
21
|
-
default: null,
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
data() {
|
|
25
|
-
return {
|
|
26
|
-
source: null,
|
|
27
|
-
};
|
|
28
|
-
},
|
|
29
|
-
watch: {
|
|
30
|
-
src: {
|
|
31
|
-
handler(val) {
|
|
32
|
-
if (typeof val === 'string') {
|
|
33
|
-
this.source = val;
|
|
34
|
-
} else if (val instanceof Promise) {
|
|
35
|
-
val.then(data => {
|
|
36
|
-
// async import()
|
|
37
|
-
if (typeof data === 'object' && data.default) {
|
|
38
|
-
this.source = data.default;
|
|
39
|
-
} else if (typeof data === 'string') {
|
|
40
|
-
this.source = data;
|
|
41
|
-
} else if (data instanceof File) {
|
|
42
|
-
loadFile(data).then(source => (this.source = source));
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
} else if (val instanceof File) {
|
|
46
|
-
loadFile(val).then(source => (this.source = source));
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
immediate: true,
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
render(h) {
|
|
53
|
-
const { source } = this;
|
|
54
|
-
return source ? h('img', { attrs: { src: source } }) : this.$slots.default;
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
</script>
|
|
1
|
+
<script>
|
|
2
|
+
/**
|
|
3
|
+
* @param {File} file
|
|
4
|
+
* @return {Promise<string>}
|
|
5
|
+
*/
|
|
6
|
+
const loadFile = file => {
|
|
7
|
+
return new Promise(resolve => {
|
|
8
|
+
const fr = new FileReader();
|
|
9
|
+
fr.addEventListener('load', ({ target }) => resolve(target.result));
|
|
10
|
+
fr.readAsDataURL(file);
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
props: {
|
|
16
|
+
/**
|
|
17
|
+
* Image source (String, File, Promise<Module>, Promise<File>)
|
|
18
|
+
*/
|
|
19
|
+
src: {
|
|
20
|
+
type: [String, File, Promise],
|
|
21
|
+
default: null,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
data() {
|
|
25
|
+
return {
|
|
26
|
+
source: null,
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
watch: {
|
|
30
|
+
src: {
|
|
31
|
+
handler(val) {
|
|
32
|
+
if (typeof val === 'string') {
|
|
33
|
+
this.source = val;
|
|
34
|
+
} else if (val instanceof Promise) {
|
|
35
|
+
val.then(data => {
|
|
36
|
+
// async import()
|
|
37
|
+
if (typeof data === 'object' && data.default) {
|
|
38
|
+
this.source = data.default;
|
|
39
|
+
} else if (typeof data === 'string') {
|
|
40
|
+
this.source = data;
|
|
41
|
+
} else if (data instanceof File) {
|
|
42
|
+
loadFile(data).then(source => (this.source = source));
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
} else if (val instanceof File) {
|
|
46
|
+
loadFile(val).then(source => (this.source = source));
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
immediate: true,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
render(h) {
|
|
53
|
+
const { source } = this;
|
|
54
|
+
return source ? h('img', { attrs: { src: source } }) : this.$slots.default;
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
</script>
|
|
@@ -1,115 +1,115 @@
|
|
|
1
|
-
Simple example
|
|
2
|
-
|
|
3
|
-
```vue
|
|
4
|
-
<template>
|
|
5
|
-
<div class="pad-l5">
|
|
6
|
-
<p>value: {{ model }}</p>
|
|
7
|
-
<input-autocomplete class="w-6-12" v-model="model" v-bind="props"></input-autocomplete>
|
|
8
|
-
</div>
|
|
9
|
-
</template>
|
|
10
|
-
<script>
|
|
11
|
-
export default {
|
|
12
|
-
data() {
|
|
13
|
-
return {
|
|
14
|
-
model: '',
|
|
15
|
-
props: {
|
|
16
|
-
options: [
|
|
17
|
-
'angular',
|
|
18
|
-
'aurelia',
|
|
19
|
-
'backbone',
|
|
20
|
-
'ember',
|
|
21
|
-
'meteor',
|
|
22
|
-
'react',
|
|
23
|
-
'riot',
|
|
24
|
-
'stencil',
|
|
25
|
-
'svelte',
|
|
26
|
-
'vue',
|
|
27
|
-
],
|
|
28
|
-
placeholder: 'New tag here',
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
</script>
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Advanced example. Async filtering, debounce, slots
|
|
37
|
-
|
|
38
|
-
```vue
|
|
39
|
-
<template>
|
|
40
|
-
<div class="pad-l5">
|
|
41
|
-
<p>value: {{ model }}</p>
|
|
42
|
-
<input-autocomplete class="w-6-12" v-model="model" v-bind="props">
|
|
43
|
-
<template #loading>
|
|
44
|
-
<mark>loading</mark>
|
|
45
|
-
</template>
|
|
46
|
-
<template #input="{ id, value, inputBinds, inputEvents }">
|
|
47
|
-
<input
|
|
48
|
-
class="w-100"
|
|
49
|
-
:id="id"
|
|
50
|
-
type="text"
|
|
51
|
-
:value="value"
|
|
52
|
-
v-bind="inputBinds"
|
|
53
|
-
v-on="inputEvents"
|
|
54
|
-
style="border:none; outline:none"
|
|
55
|
-
/>
|
|
56
|
-
</template>
|
|
57
|
-
<template #dropdown-header>
|
|
58
|
-
<div class="pad-3">header</div>
|
|
59
|
-
</template>
|
|
60
|
-
<template #noresults>
|
|
61
|
-
<div class="pad-3 text-muted">Nothing found :(</div>
|
|
62
|
-
</template>
|
|
63
|
-
<template #option="{ option, optionIndex, valueLocal, selectOption, cursorIndex }">
|
|
64
|
-
<li
|
|
65
|
-
:class="{ 'bg-yellow': optionIndex == cursorIndex }"
|
|
66
|
-
@click="selectOption(option)"
|
|
67
|
-
>
|
|
68
|
-
<div v-html="option.replace(valueLocal, '<b>' + valueLocal + '</b>')"></div>
|
|
69
|
-
</li>
|
|
70
|
-
</template>
|
|
71
|
-
<template #dropdown-footer>
|
|
72
|
-
<div class="pad-3">footer</div>
|
|
73
|
-
</template>
|
|
74
|
-
</input-autocomplete>
|
|
75
|
-
</div>
|
|
76
|
-
</template>
|
|
77
|
-
<script>
|
|
78
|
-
// fake api
|
|
79
|
-
const api = {
|
|
80
|
-
autocomplete(query) {
|
|
81
|
-
return new Promise(resolve => {
|
|
82
|
-
setTimeout(() => {
|
|
83
|
-
let arr = [
|
|
84
|
-
'angular',
|
|
85
|
-
'aurelia',
|
|
86
|
-
'backbone',
|
|
87
|
-
'ember',
|
|
88
|
-
'meteor',
|
|
89
|
-
'react',
|
|
90
|
-
'riot',
|
|
91
|
-
'stencil',
|
|
92
|
-
'svelte',
|
|
93
|
-
'vue',
|
|
94
|
-
].filter(item => item.indexOf(query) === 0);
|
|
95
|
-
resolve(arr);
|
|
96
|
-
}, 500);
|
|
97
|
-
});
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
export default {
|
|
101
|
-
data() {
|
|
102
|
-
return {
|
|
103
|
-
model: '',
|
|
104
|
-
props: {
|
|
105
|
-
options: [],
|
|
106
|
-
placeholder: 'New tag here (min 1 letter)',
|
|
107
|
-
minLength: 1,
|
|
108
|
-
filter: api.autocomplete,
|
|
109
|
-
filterDebounce: 250,
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
|
-
},
|
|
113
|
-
};
|
|
114
|
-
</script>
|
|
115
|
-
```
|
|
1
|
+
Simple example
|
|
2
|
+
|
|
3
|
+
```vue
|
|
4
|
+
<template>
|
|
5
|
+
<div class="pad-l5">
|
|
6
|
+
<p>value: {{ model }}</p>
|
|
7
|
+
<input-autocomplete class="w-6-12" v-model="model" v-bind="props"></input-autocomplete>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
<script>
|
|
11
|
+
export default {
|
|
12
|
+
data() {
|
|
13
|
+
return {
|
|
14
|
+
model: '',
|
|
15
|
+
props: {
|
|
16
|
+
options: [
|
|
17
|
+
'angular',
|
|
18
|
+
'aurelia',
|
|
19
|
+
'backbone',
|
|
20
|
+
'ember',
|
|
21
|
+
'meteor',
|
|
22
|
+
'react',
|
|
23
|
+
'riot',
|
|
24
|
+
'stencil',
|
|
25
|
+
'svelte',
|
|
26
|
+
'vue',
|
|
27
|
+
],
|
|
28
|
+
placeholder: 'New tag here',
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
</script>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Advanced example. Async filtering, debounce, slots
|
|
37
|
+
|
|
38
|
+
```vue
|
|
39
|
+
<template>
|
|
40
|
+
<div class="pad-l5">
|
|
41
|
+
<p>value: {{ model }}</p>
|
|
42
|
+
<input-autocomplete class="w-6-12" v-model="model" v-bind="props">
|
|
43
|
+
<template #loading>
|
|
44
|
+
<mark>loading</mark>
|
|
45
|
+
</template>
|
|
46
|
+
<template #input="{ id, value, inputBinds, inputEvents }">
|
|
47
|
+
<input
|
|
48
|
+
class="w-100"
|
|
49
|
+
:id="id"
|
|
50
|
+
type="text"
|
|
51
|
+
:value="value"
|
|
52
|
+
v-bind="inputBinds"
|
|
53
|
+
v-on="inputEvents"
|
|
54
|
+
style="border:none; outline:none"
|
|
55
|
+
/>
|
|
56
|
+
</template>
|
|
57
|
+
<template #dropdown-header>
|
|
58
|
+
<div class="pad-3">header</div>
|
|
59
|
+
</template>
|
|
60
|
+
<template #noresults>
|
|
61
|
+
<div class="pad-3 text-muted">Nothing found :(</div>
|
|
62
|
+
</template>
|
|
63
|
+
<template #option="{ option, optionIndex, valueLocal, selectOption, cursorIndex }">
|
|
64
|
+
<li
|
|
65
|
+
:class="{ 'bg-yellow': optionIndex == cursorIndex }"
|
|
66
|
+
@click="selectOption(option)"
|
|
67
|
+
>
|
|
68
|
+
<div v-html="option.replace(valueLocal, '<b>' + valueLocal + '</b>')"></div>
|
|
69
|
+
</li>
|
|
70
|
+
</template>
|
|
71
|
+
<template #dropdown-footer>
|
|
72
|
+
<div class="pad-3">footer</div>
|
|
73
|
+
</template>
|
|
74
|
+
</input-autocomplete>
|
|
75
|
+
</div>
|
|
76
|
+
</template>
|
|
77
|
+
<script>
|
|
78
|
+
// fake api
|
|
79
|
+
const api = {
|
|
80
|
+
autocomplete(query) {
|
|
81
|
+
return new Promise(resolve => {
|
|
82
|
+
setTimeout(() => {
|
|
83
|
+
let arr = [
|
|
84
|
+
'angular',
|
|
85
|
+
'aurelia',
|
|
86
|
+
'backbone',
|
|
87
|
+
'ember',
|
|
88
|
+
'meteor',
|
|
89
|
+
'react',
|
|
90
|
+
'riot',
|
|
91
|
+
'stencil',
|
|
92
|
+
'svelte',
|
|
93
|
+
'vue',
|
|
94
|
+
].filter(item => item.indexOf(query) === 0);
|
|
95
|
+
resolve(arr);
|
|
96
|
+
}, 500);
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
export default {
|
|
101
|
+
data() {
|
|
102
|
+
return {
|
|
103
|
+
model: '',
|
|
104
|
+
props: {
|
|
105
|
+
options: [],
|
|
106
|
+
placeholder: 'New tag here (min 1 letter)',
|
|
107
|
+
minLength: 1,
|
|
108
|
+
filter: api.autocomplete,
|
|
109
|
+
filterDebounce: 250,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
</script>
|
|
115
|
+
```
|