goodteditor-ui 1.0.88 → 1.0.90
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/package.json
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
```vue
|
|
2
|
+
<template>
|
|
3
|
+
<div class="pad-l5">
|
|
4
|
+
<p>model: {{ model }}</p>
|
|
5
|
+
<ui-editable-text v-model="model" v-bind="options"></ui-editable-text>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
<script>
|
|
9
|
+
import UiEditableText from './EditableText.vue';
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
components: { UiEditableText },
|
|
13
|
+
data: () => ({
|
|
14
|
+
model: 'hello world',
|
|
15
|
+
options: {
|
|
16
|
+
size: 'large'
|
|
17
|
+
}
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
</script>
|
|
21
|
+
```
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ui-editable-text" @click="onRootClick">
|
|
3
|
+
<div class="ui-editable-text-label cursor-pointer text-truncate" :class="labelClass">
|
|
4
|
+
<!--
|
|
5
|
+
@slot
|
|
6
|
+
@binding {string} value current value
|
|
7
|
+
-->
|
|
8
|
+
<slot v-bind="{ value }">{{ value }}</slot>
|
|
9
|
+
</div>
|
|
10
|
+
<input
|
|
11
|
+
v-if="isEditable"
|
|
12
|
+
:value="value"
|
|
13
|
+
:class="inputClass"
|
|
14
|
+
class="ui-editable-text-input input h-100"
|
|
15
|
+
type="text"
|
|
16
|
+
ref="input"
|
|
17
|
+
@change="onValueChange" />
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
<script>
|
|
21
|
+
import { domEvent } from './utils/Helpers';
|
|
22
|
+
|
|
23
|
+
const Size = {
|
|
24
|
+
SMALL: { name: 'small', labelClass: ['text-small'], inputClass: ['input-small'] },
|
|
25
|
+
NORMAL: { name: 'normal', labelClass: [], inputClass: [] },
|
|
26
|
+
LARGE: { name: 'large', labelClass: ['text-large'], inputClass: ['input-large'] },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default {
|
|
30
|
+
props: {
|
|
31
|
+
/**
|
|
32
|
+
* @vmodel
|
|
33
|
+
* @example lorem ipsum sit dolor
|
|
34
|
+
*/
|
|
35
|
+
value: {
|
|
36
|
+
type: String,
|
|
37
|
+
default: ''
|
|
38
|
+
},
|
|
39
|
+
/**
|
|
40
|
+
* @default normal
|
|
41
|
+
* @values small,normal,large
|
|
42
|
+
*/
|
|
43
|
+
size: {
|
|
44
|
+
type: String,
|
|
45
|
+
default: Size.NORMAL.name,
|
|
46
|
+
validator: (val) =>
|
|
47
|
+
Object.values(Size)
|
|
48
|
+
.map(({ name }) => name)
|
|
49
|
+
.includes(val)
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
data: () => ({
|
|
53
|
+
isEditable: false,
|
|
54
|
+
onDocClickDisposable: null
|
|
55
|
+
}),
|
|
56
|
+
computed: {
|
|
57
|
+
labelClass() {
|
|
58
|
+
const { isEditable, size } = this;
|
|
59
|
+
const classes = [];
|
|
60
|
+
const sizeDef = Object.values(Size).find(({ name }) => name === size);
|
|
61
|
+
|
|
62
|
+
classes.push(...sizeDef.labelClass);
|
|
63
|
+
|
|
64
|
+
if (isEditable) {
|
|
65
|
+
classes.push('invisible');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return classes;
|
|
69
|
+
},
|
|
70
|
+
inputClass() {
|
|
71
|
+
const sizeDef = Object.values(Size).find(({ name }) => name === this.size);
|
|
72
|
+
return sizeDef.inputClass;
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
beforeDestroy() {
|
|
76
|
+
const { onDocClickDisposable } = this;
|
|
77
|
+
if (onDocClickDisposable != null) {
|
|
78
|
+
onDocClickDisposable();
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
methods: {
|
|
82
|
+
onRootClick() {
|
|
83
|
+
if (this.isEditable) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
this.isEditable = true;
|
|
87
|
+
this.$nextTick(() => {
|
|
88
|
+
const { input } = this.$refs;
|
|
89
|
+
input.select();
|
|
90
|
+
setTimeout(() => {
|
|
91
|
+
this.onDocClickDisposable = domEvent(document, 'click', this.onDocClick);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
onValueChange({ target }) {
|
|
96
|
+
const { value: valueNew } = target;
|
|
97
|
+
if (this.value !== valueNew) {
|
|
98
|
+
this.$emit('input', valueNew);
|
|
99
|
+
this.$emit('change', valueNew);
|
|
100
|
+
}
|
|
101
|
+
this.isEditable = false;
|
|
102
|
+
this.onDocClickDisposable();
|
|
103
|
+
},
|
|
104
|
+
onDocClick({ target }) {
|
|
105
|
+
if (this.$el.contains(target)) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
this.isEditable = false;
|
|
109
|
+
this.onDocClickDisposable();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
</script>
|
|
114
|
+
<style lang="less" scoped>
|
|
115
|
+
.ui-editable-text {
|
|
116
|
+
position: relative;
|
|
117
|
+
display: inline-flex;
|
|
118
|
+
|
|
119
|
+
&-label {
|
|
120
|
+
&:hover {
|
|
121
|
+
color: var(--color-primary);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
&-input {
|
|
125
|
+
position: absolute;
|
|
126
|
+
top: 0;
|
|
127
|
+
left: -0.5rem;
|
|
128
|
+
width: calc(100% + 1rem);
|
|
129
|
+
border: none;
|
|
130
|
+
padding-top: 0;
|
|
131
|
+
padding-bottom: 0;
|
|
132
|
+
min-height: auto;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
</style>
|
|
@@ -77,6 +77,18 @@ const generateGetBoundingClientRect = (x = 0, y = 0) => () => ({
|
|
|
77
77
|
left: x,
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
+
/**
|
|
81
|
+
* @param {EventTarget} target
|
|
82
|
+
* @param {string} type
|
|
83
|
+
* @param {EventListenerOrEventListenerObject} listener
|
|
84
|
+
* @param {AddEventListenerOptions} options
|
|
85
|
+
* @returns
|
|
86
|
+
*/
|
|
87
|
+
const domEvent = (target, type, listener, options = undefined) => {
|
|
88
|
+
target.addEventListener(type, listener, options);
|
|
89
|
+
return () => target.removeEventListener(type, listener, options);
|
|
90
|
+
};
|
|
91
|
+
|
|
80
92
|
export {
|
|
81
93
|
scrollIntoView,
|
|
82
94
|
isDateValid,
|
|
@@ -85,6 +97,7 @@ export {
|
|
|
85
97
|
Position,
|
|
86
98
|
TriggerOn,
|
|
87
99
|
debounce,
|
|
100
|
+
domEvent,
|
|
88
101
|
useIntersectionObserver,
|
|
89
102
|
generateGetBoundingClientRect,
|
|
90
103
|
};
|