jobdone-shared-files 1.0.2 → 1.0.4

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/tagEditor.vue CHANGED
@@ -1,264 +1,264 @@
1
- <template>
2
- <div class="tag-editor" v-if="tagAry">
3
- <div class="main-cont">
4
- <div class="form-control form-control-sm" :class="disabled ? 'is-disabled' : ''">
5
- <template v-if="tagAry.length">
6
- <div class="badge rounded-pill" :class="disabled ? 'badge-outline-gray ' : 'badge-outline-purple'"
7
- v-for="(tag, index) in tagAry" :key="index" :title="tag">
8
- <div class="tag-text">{{ tag }}</div>
9
- <div class="remove-btn-box" v-if="!disabled">
10
- <button type="button" class="remove-btn" @click="removeTag(index)"><span
11
- class="material-icons">close</span>
12
- </button>
13
- </div>
14
- </div>
15
- </template>
16
- <input v-if="!disabled" class="new-tag-input" list="datalistOptions" type="text" :placeholder="placeholder"
17
- v-model.trim="newTag" @keydown.enter="addTag" @keyup="keyupFunction">
18
- <datalist id="datalistOptions" v-if="autoCompleteShow">
19
- <option :value="opt" v-for="(opt, idx) in autoCompleteOption" :key="idx">{{ opt }}</option>
20
- </datalist>
21
- </div>
22
- </div>
23
- <div class="helper-text-box" v-if="!disabled">
24
- <small class="helper-text">在輸入框中輸入文字後,按下鍵盤的"Enter"鍵,即可增加標籤。(標籤僅接受中文、英文、數字、下底線)</small>
25
- </div>
26
- </div>
27
- </template>
28
- <script>
29
- // enum Data & Functions
30
- // import { } from '../common/enum.js'
31
-
32
- // vue & bootstrap
33
- import { ref, reactive, onMounted, computed } from 'vue'
34
- // import { } from 'bootstrap';
35
-
36
- // plugins
37
- // import { v4 as uuidv4 } from 'uuid';
38
- // import { useVuelidate } from '@vuelidate/core'
39
- // import { required } from '@vuelidate/validators'
40
- // import { SwalSuccess, SwalConfirmDelete } from '../common/sweetalert.js';
41
-
42
- // vue components
43
- // import Loading from "./vueLoadingOverlay.vue";
44
-
45
- export default {
46
- props: {
47
- defaultTagList: {
48
- type: Array,
49
- default: () => []
50
- },
51
- placeholder: {
52
- type: String,
53
- default: '請在此處輸入標籤文字'
54
- },
55
- autoComplete: {
56
- type: Boolean,
57
- default: true
58
- },
59
- autoCompleteOption: {
60
- type: Array,
61
- default: () => []
62
- },
63
- disabled: {
64
- type: Boolean,
65
- default: false
66
- }
67
- },
68
- setup(props, { emit }) {
69
- // 基本資料
70
- const tagAry = reactive([])
71
- const newTag = ref('')
72
-
73
- const autoCompleteShow = computed(() => {
74
- let show = props.autoComplete
75
- if (!newTag.value || props.autoCompleteOption.length < 1) {
76
- show = false
77
- }
78
- return show
79
- })
80
- // 輸入時 AutoComplete
81
- var autoCompleteTimer
82
- function updateAutoCompleteOption() {
83
- clearTimeout(autoCompleteTimer);
84
- if (newTag.value) {
85
- autoCompleteTimer = setTimeout(() => {
86
- emit('update-auto-complete-option', newTag.value);
87
- }, 500);
88
- }
89
- }
90
-
91
- // 刷新預設選中內容
92
- function getDefaultTag(updateData = []) {
93
- tagAry.splice(0, tagAry.length, ...updateData)
94
- }
95
- function keyupFunction() {
96
- if (props.autoCompleteOption) {
97
- updateAutoCompleteOption()
98
- }
99
- newTag.value = newTag.value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5]/g, '_')
100
- }
101
-
102
- // 重複標籤禁止新增
103
- var isDuplicate = computed(() => {
104
- return newTag.value ? !!tagAry.find(tag => tag == newTag.value) : false
105
- })
106
-
107
- // 增加Tag
108
- function addTag() {
109
- if (newTag.value && !isDuplicate.value) {
110
- tagAry.push(newTag.value)
111
- }
112
- newTag.value = ''
113
- }
114
- // 移除Tag
115
- function removeTag(index) {
116
- tagAry.splice(index, 1)
117
- }
118
- function reset() {
119
- tagAry.splice(0, tagAry.length)
120
- newTag.value = ''
121
- }
122
-
123
- onMounted(() => {
124
- getDefaultTag(props.defaultTagList)
125
- })
126
- return {
127
- tagAry,
128
- newTag,
129
- addTag,
130
- removeTag,
131
- updateAutoCompleteOption,
132
- autoCompleteTimer,
133
- autoCompleteShow,
134
- reset,
135
- keyupFunction,
136
- isDuplicate,
137
- getDefaultTag
138
- }
139
- }
140
- }
141
- </script>
142
-
143
- <style lang="scss" scoped>
144
- .tag-editor {
145
- background: var(--bs-gray-100);
146
- border-radius: var(--bs-border-radius);
147
- padding: .5rem;
148
-
149
- .helper-text-box {
150
- text-align: start;
151
-
152
- .helper-text {
153
- font-size: 0.75rem;
154
- color: var(--bs-gray-500);
155
- }
156
- }
157
-
158
- .main-cont {
159
- position: relative;
160
-
161
- .auto-complete-box {
162
- all: unset;
163
- display: none;
164
- visibility: hidden;
165
- position: absolute;
166
- width: 90%;
167
- overflow: hidden;
168
-
169
- &.show {
170
- visibility: visible;
171
- display: block;
172
- position: absolute;
173
- top: calc(100% + 0.25rem);
174
- background: #fff;
175
- border: 1px solid var(--bs-gray-300);
176
- border-radius: var(--bs-border-radius);
177
- box-shadow: var(--bs-box-shadow);
178
- }
179
-
180
- .opt-item {
181
- padding: 0.5rem;
182
- cursor: pointer;
183
- overflow: hidden;
184
- text-overflow: ellipsis;
185
-
186
- &:not(:last-child) {
187
- border-bottom: 1px solid var(--bs-gray-300);
188
- }
189
- }
190
- }
191
- }
192
-
193
- .form-control {
194
- display: flex;
195
- align-items: center;
196
- flex-wrap: wrap;
197
- padding: .5rem .5rem .25rem .5rem;
198
-
199
- &.is-disabled:hover {
200
- cursor: not-allowed;
201
- }
202
- }
203
-
204
- .new-tag-input {
205
- all: unset;
206
- flex-grow: 1;
207
- margin-bottom: .25rem;
208
- background: var(--bs-gray-100);
209
- padding: .25rem .75rem;
210
- border-radius: 99px;
211
- border: 1px solid rgba(#000, 0);
212
- }
213
-
214
- .badge.rounded-pill {
215
- margin: 0 .25rem .25rem 0;
216
- display: inline-flex;
217
- align-items: stretch;
218
- overflow: hidden;
219
-
220
- .tag-text {
221
- margin: auto;
222
- overflow: hidden;
223
- text-overflow: ellipsis;
224
- }
225
-
226
- .remove-btn-box {
227
- display: flex;
228
- align-items: stretch;
229
-
230
- &::before {
231
- display: block;
232
- content: ' ';
233
- height: 100%;
234
- border-left: 1px solid var(--bs-gray-300);
235
- margin: 0 0.25rem;
236
- }
237
- }
238
-
239
- .remove-btn {
240
- all: unset;
241
- display: flex;
242
- align-items: center;
243
- justify-content: center;
244
-
245
- .material-icons {
246
- font-size: 16px;
247
- line-height: 16px;
248
- color: var(--bs-purple);
249
- opacity: .5;
250
- transition: .3s;
251
- }
252
-
253
- &:hover {
254
- cursor: pointer;
255
-
256
- .material-icons {
257
- opacity: 1;
258
- }
259
- }
260
- }
261
- }
262
-
263
- }
1
+ <template>
2
+ <div class="tag-editor" v-if="tagAry">
3
+ <div class="main-cont">
4
+ <div class="form-control form-control-sm" :class="disabled ? 'is-disabled' : ''">
5
+ <template v-if="tagAry.length">
6
+ <div class="badge rounded-pill" :class="disabled ? 'badge-outline-gray ' : 'badge-outline-purple'"
7
+ v-for="(tag, index) in tagAry" :key="index" :title="tag">
8
+ <div class="tag-text">{{ tag }}</div>
9
+ <div class="remove-btn-box" v-if="!disabled">
10
+ <button type="button" class="remove-btn" @click="removeTag(index)"><span
11
+ class="material-icons">close</span>
12
+ </button>
13
+ </div>
14
+ </div>
15
+ </template>
16
+ <input v-if="!disabled" class="new-tag-input" list="datalistOptions" type="text" :placeholder="placeholder"
17
+ v-model.trim="newTag" @keydown.enter="addTag" @keyup="keyupFunction">
18
+ <datalist id="datalistOptions" v-if="autoCompleteShow">
19
+ <option :value="opt" v-for="(opt, idx) in autoCompleteOption" :key="idx">{{ opt }}</option>
20
+ </datalist>
21
+ </div>
22
+ </div>
23
+ <div class="helper-text-box" v-if="!disabled">
24
+ <small class="helper-text">在輸入框中輸入文字後,按下鍵盤的"Enter"鍵,即可增加標籤。(標籤僅接受中文、英文、數字、下底線)</small>
25
+ </div>
26
+ </div>
27
+ </template>
28
+ <script>
29
+ // enum Data & Functions
30
+ // import { } from '../common/enum.js'
31
+
32
+ // vue & bootstrap
33
+ import { ref, reactive, onMounted, computed } from 'vue'
34
+ // import { } from 'bootstrap';
35
+
36
+ // plugins
37
+ // import { v4 as uuidv4 } from 'uuid';
38
+ // import { useVuelidate } from '@vuelidate/core'
39
+ // import { required } from '@vuelidate/validators'
40
+ // import { SwalSuccess, SwalConfirmDelete } from '../common/sweetalert.js';
41
+
42
+ // vue components
43
+ // import Loading from "./vueLoadingOverlay.vue";
44
+
45
+ export default {
46
+ props: {
47
+ defaultTagList: {
48
+ type: Array,
49
+ default: () => []
50
+ },
51
+ placeholder: {
52
+ type: String,
53
+ default: '請在此處輸入標籤文字'
54
+ },
55
+ autoComplete: {
56
+ type: Boolean,
57
+ default: true
58
+ },
59
+ autoCompleteOption: {
60
+ type: Array,
61
+ default: () => []
62
+ },
63
+ disabled: {
64
+ type: Boolean,
65
+ default: false
66
+ }
67
+ },
68
+ setup(props, { emit }) {
69
+ // 基本資料
70
+ const tagAry = reactive([])
71
+ const newTag = ref('')
72
+
73
+ const autoCompleteShow = computed(() => {
74
+ let show = props.autoComplete
75
+ if (!newTag.value || props.autoCompleteOption.length < 1) {
76
+ show = false
77
+ }
78
+ return show
79
+ })
80
+ // 輸入時 AutoComplete
81
+ var autoCompleteTimer
82
+ function updateAutoCompleteOption() {
83
+ clearTimeout(autoCompleteTimer);
84
+ if (newTag.value) {
85
+ autoCompleteTimer = setTimeout(() => {
86
+ emit('update-auto-complete-option', newTag.value);
87
+ }, 500);
88
+ }
89
+ }
90
+
91
+ // 刷新預設選中內容
92
+ function getDefaultTag(updateData = []) {
93
+ tagAry.splice(0, tagAry.length, ...updateData)
94
+ }
95
+ function keyupFunction() {
96
+ if (props.autoCompleteOption) {
97
+ updateAutoCompleteOption()
98
+ }
99
+ newTag.value = newTag.value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5]/g, '_')
100
+ }
101
+
102
+ // 重複標籤禁止新增
103
+ var isDuplicate = computed(() => {
104
+ return newTag.value ? !!tagAry.find(tag => tag == newTag.value) : false
105
+ })
106
+
107
+ // 增加Tag
108
+ function addTag() {
109
+ if (newTag.value && !isDuplicate.value) {
110
+ tagAry.push(newTag.value)
111
+ }
112
+ newTag.value = ''
113
+ }
114
+ // 移除Tag
115
+ function removeTag(index) {
116
+ tagAry.splice(index, 1)
117
+ }
118
+ function reset() {
119
+ tagAry.splice(0, tagAry.length)
120
+ newTag.value = ''
121
+ }
122
+
123
+ onMounted(() => {
124
+ getDefaultTag(props.defaultTagList)
125
+ })
126
+ return {
127
+ tagAry,
128
+ newTag,
129
+ addTag,
130
+ removeTag,
131
+ updateAutoCompleteOption,
132
+ autoCompleteTimer,
133
+ autoCompleteShow,
134
+ reset,
135
+ keyupFunction,
136
+ isDuplicate,
137
+ getDefaultTag
138
+ }
139
+ }
140
+ }
141
+ </script>
142
+
143
+ <style lang="scss" scoped>
144
+ .tag-editor {
145
+ background: var(--bs-gray-100);
146
+ border-radius: var(--bs-border-radius);
147
+ padding: .5rem;
148
+
149
+ .helper-text-box {
150
+ text-align: start;
151
+
152
+ .helper-text {
153
+ font-size: 0.75rem;
154
+ color: var(--bs-gray-500);
155
+ }
156
+ }
157
+
158
+ .main-cont {
159
+ position: relative;
160
+
161
+ .auto-complete-box {
162
+ all: unset;
163
+ display: none;
164
+ visibility: hidden;
165
+ position: absolute;
166
+ width: 90%;
167
+ overflow: hidden;
168
+
169
+ &.show {
170
+ visibility: visible;
171
+ display: block;
172
+ position: absolute;
173
+ top: calc(100% + 0.25rem);
174
+ background: #fff;
175
+ border: 1px solid var(--bs-gray-300);
176
+ border-radius: var(--bs-border-radius);
177
+ box-shadow: var(--bs-box-shadow);
178
+ }
179
+
180
+ .opt-item {
181
+ padding: 0.5rem;
182
+ cursor: pointer;
183
+ overflow: hidden;
184
+ text-overflow: ellipsis;
185
+
186
+ &:not(:last-child) {
187
+ border-bottom: 1px solid var(--bs-gray-300);
188
+ }
189
+ }
190
+ }
191
+ }
192
+
193
+ .form-control {
194
+ display: flex;
195
+ align-items: center;
196
+ flex-wrap: wrap;
197
+ padding: .5rem .5rem .25rem .5rem;
198
+
199
+ &.is-disabled:hover {
200
+ cursor: not-allowed;
201
+ }
202
+ }
203
+
204
+ .new-tag-input {
205
+ all: unset;
206
+ flex-grow: 1;
207
+ margin-bottom: .25rem;
208
+ background: var(--bs-gray-100);
209
+ padding: .25rem .75rem;
210
+ border-radius: 99px;
211
+ border: 1px solid rgba(#000, 0);
212
+ }
213
+
214
+ .badge.rounded-pill {
215
+ margin: 0 .25rem .25rem 0;
216
+ display: inline-flex;
217
+ align-items: stretch;
218
+ overflow: hidden;
219
+
220
+ .tag-text {
221
+ margin: auto;
222
+ overflow: hidden;
223
+ text-overflow: ellipsis;
224
+ }
225
+
226
+ .remove-btn-box {
227
+ display: flex;
228
+ align-items: stretch;
229
+
230
+ &::before {
231
+ display: block;
232
+ content: ' ';
233
+ height: 100%;
234
+ border-left: 1px solid var(--bs-gray-300);
235
+ margin: 0 0.25rem;
236
+ }
237
+ }
238
+
239
+ .remove-btn {
240
+ all: unset;
241
+ display: flex;
242
+ align-items: center;
243
+ justify-content: center;
244
+
245
+ .material-icons {
246
+ font-size: 16px;
247
+ line-height: 16px;
248
+ color: var(--bs-purple);
249
+ opacity: .5;
250
+ transition: .3s;
251
+ }
252
+
253
+ &:hover {
254
+ cursor: pointer;
255
+
256
+ .material-icons {
257
+ opacity: 1;
258
+ }
259
+ }
260
+ }
261
+ }
262
+
263
+ }
264
264
  </style>
package/tree.vue CHANGED
@@ -1,69 +1,69 @@
1
- <template>
2
- <form ref="form">
3
- <tree-item v-for="(item, index) in items" :key="item.id" :item="item" :index="index" :click-item="clickItem" :active-id="activeId" :tree-item-class="treeItemClass">
4
- <template v-slot:icon>
5
- <slot name="icon"></slot>
6
- </template>
7
- </tree-item>
8
- </form>
9
- </template>
10
-
11
- <script>
12
- import { ref, computed } from 'vue';
13
- import TreeItem from './treeItem.vue';
14
- export default {
15
- props: {
16
- items: {
17
- type: Array,
18
- default: function () {
19
- return [];
20
- }
21
- },
22
- clickItem: {
23
- type: Function
24
- },
25
- size: {
26
- type: String,
27
- default: ""
28
- },
29
- bgColor: {
30
- type: String,
31
- default: ""
32
- }
33
- },
34
- components: {
35
- TreeItem
36
- },
37
- setup(props, { emit }) {
38
- const form = ref(null);
39
- const activeId = ref("");
40
- const clickItem = (item) => {
41
- activeId.value = item.id;
42
- props.clickItem(item);
43
- };
44
- const treeItemClass = computed(() => {
45
- var classList = [];
46
- if (props.size == 'sm') {
47
- classList.push('tree-item-sm');
48
- }
49
- if (props.bgColor == 'white') {
50
- classList.push('tree-item-in-white');
51
- }
52
- return classList;
53
- });
54
- const reset = () => {
55
- activeId.value = "";
56
- form.reset();
57
- };
58
- return {
59
- form: form,
60
- treeItemClass: treeItemClass,
61
- activeId: activeId,
62
- clickItem: clickItem,
63
- reset: reset
64
- };
65
- }
66
- }
67
- </script>
68
- <style>
69
- </style>
1
+ <template>
2
+ <form ref="form">
3
+ <tree-item v-for="(item, index) in items" :key="item.id" :item="item" :index="index" :click-item="clickItem" :active-id="activeId" :tree-item-class="treeItemClass">
4
+ <template v-slot:icon>
5
+ <slot name="icon"></slot>
6
+ </template>
7
+ </tree-item>
8
+ </form>
9
+ </template>
10
+
11
+ <script>
12
+ import { ref, computed } from 'vue';
13
+ import TreeItem from './treeItem.vue';
14
+ export default {
15
+ props: {
16
+ items: {
17
+ type: Array,
18
+ default: function () {
19
+ return [];
20
+ }
21
+ },
22
+ clickItem: {
23
+ type: Function
24
+ },
25
+ size: {
26
+ type: String,
27
+ default: ""
28
+ },
29
+ bgColor: {
30
+ type: String,
31
+ default: ""
32
+ }
33
+ },
34
+ components: {
35
+ TreeItem
36
+ },
37
+ setup(props, { emit }) {
38
+ const form = ref(null);
39
+ const activeId = ref("");
40
+ const clickItem = (item) => {
41
+ activeId.value = item.id;
42
+ props.clickItem(item);
43
+ };
44
+ const treeItemClass = computed(() => {
45
+ var classList = [];
46
+ if (props.size == 'sm') {
47
+ classList.push('tree-item-sm');
48
+ }
49
+ if (props.bgColor == 'white') {
50
+ classList.push('tree-item-in-white');
51
+ }
52
+ return classList;
53
+ });
54
+ const reset = () => {
55
+ activeId.value = "";
56
+ form.reset();
57
+ };
58
+ return {
59
+ form: form,
60
+ treeItemClass: treeItemClass,
61
+ activeId: activeId,
62
+ clickItem: clickItem,
63
+ reset: reset
64
+ };
65
+ }
66
+ }
67
+ </script>
68
+ <style>
69
+ </style>