jobdone-shared-files 1.1.10 → 1.1.12

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 (2) hide show
  1. package/package.json +1 -1
  2. package/tagEditor.vue +156 -112
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jobdone-shared-files",
3
- "version": "1.1.10",
3
+ "version": "1.1.12",
4
4
  "description": "Shared JS and SCSS for Jobdone Enterprise.",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/tagEditor.vue CHANGED
@@ -13,131 +13,156 @@
13
13
  </div>
14
14
  </div>
15
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>
16
+ <template v-if="!disabled && !isMaxTagCountReached">
17
+ <input class="new-tag-input" list="datalistOptions" type="text" :placeholder="placeholder"
18
+ :maxlength="singleTagMaxLength || 50" v-model.trim="newTag" @keydown.enter="addTag($event)"
19
+ @keyup="keyupFunction">
20
+ <datalist id="datalistOptions" v-if="autoCompleteShow">
21
+ <option :value="opt" v-for="(opt, idx) in autoCompleteOption" :key="idx">{{ opt }}</option>
22
+ </datalist>
23
+ </template>
21
24
  </div>
22
25
  </div>
23
26
  <div class="helper-text-box" v-if="!disabled">
24
- <small class="helper-text">在輸入框中輸入文字後,按下鍵盤的"Enter"鍵,即可增加標籤。(標籤僅接受中文、英文、數字、下底線)</small>
27
+ <small class="helper-text">在輸入框中輸入文字後,按下鍵盤的「Enter鍵」即可增加標籤。標籤僅接受中文、英文、數字、下底線、<span class="text-danger">長度限制
28
+ {{ singleTagMaxLength }} 個字元</span>。
29
+ <template v-if="maxTagCount > 0">
30
+ <span class="text-danger">最多新增 {{ maxTagCount }} 個標籤</span>,
31
+ </template>標籤不可重複。</small>
25
32
  </div>
26
33
  </div>
27
34
  </template>
28
- <script>
35
+ <script setup>
29
36
  import { ref, reactive, onMounted, computed } from 'vue'
30
-
31
- export default {
32
- props: {
33
- defaultTagList: {
34
- type: Array,
35
- default: () => []
36
- },
37
- placeholder: {
38
- type: String,
39
- default: '請在此處輸入標籤文字'
40
- },
41
- autoComplete: {
42
- type: Boolean,
43
- default: true
44
- },
45
- autoCompleteOption: {
46
- type: Array,
47
- default: () => []
48
- },
49
- disabled: {
50
- type: Boolean,
51
- default: false
52
- }
37
+ const props = defineProps({
38
+ defaultTagList: {
39
+ type: Array,
40
+ default: () => []
53
41
  },
54
- setup(props, { emit }) {
55
- // 基本資料
56
- const tagAry = reactive([])
57
- const newTag = ref('')
58
-
59
- const autoCompleteShow = computed(() => {
60
- let show = props.autoComplete
61
- if (!newTag.value || props.autoCompleteOption.length < 1) {
62
- show = false
63
- }
64
- return show
65
- })
66
- // 輸入時 AutoComplete
67
- var autoCompleteTimer
68
- function updateAutoCompleteOption() {
69
- clearTimeout(autoCompleteTimer);
70
- if (newTag.value) {
71
- autoCompleteTimer = setTimeout(() => {
72
- emit('update-auto-complete-option', newTag.value);
73
- }, 500);
74
- }
75
- }
42
+ placeholder: {
43
+ type: String,
44
+ default: '請輸入標籤文字'
45
+ },
46
+ autoComplete: {
47
+ type: Boolean,
48
+ default: true
49
+ },
50
+ autoCompleteOption: {
51
+ type: Array,
52
+ default: () => []
53
+ },
54
+ disabled: {
55
+ type: Boolean,
56
+ default: false
57
+ },
58
+ singleTagMaxLength: {
59
+ type: Number,
60
+ default: 50
61
+ },
62
+ maxTagCount: {
63
+ type: Number,
64
+ default: 0
65
+ }
66
+ })
76
67
 
77
- // 刷新預設選中內容
78
- function getDefaultTag(updateData = []) {
79
- tagAry.splice(0, tagAry.length, ...updateData)
80
- }
81
- function keyupFunction() {
82
- if (props.autoCompleteOption) {
83
- updateAutoCompleteOption()
84
- }
85
- newTag.value = newTag.value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5]/g, '_')
86
- }
68
+ // 基本資料
69
+ const tagAry = reactive([])
70
+ const newTag = ref('')
87
71
 
88
- // 重複標籤禁止新增
89
- var isDuplicate = computed(() => {
90
- return newTag.value ? !!tagAry.find(tag => tag == newTag.value) : false
91
- })
72
+ const autoCompleteShow = computed(() => {
73
+ let show = props.autoComplete
74
+ if (!newTag.value || props.autoCompleteOption.length < 1) {
75
+ show = false
76
+ }
77
+ return show
78
+ })
92
79
 
93
- // 增加Tag
94
- function addTag() {
95
- if (newTag.value && !isDuplicate.value) {
96
- tagAry.push(newTag.value)
97
- }
98
- newTag.value = ''
99
- }
100
- // 移除Tag
101
- function removeTag(index) {
102
- tagAry.splice(index, 1)
103
- }
104
- function reset() {
105
- tagAry.splice(0, tagAry.length)
106
- newTag.value = ''
107
- }
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
+ }
108
90
 
109
- onMounted(() => {
110
- getDefaultTag(props.defaultTagList)
111
- })
112
- return {
113
- tagAry,
114
- newTag,
115
- addTag,
116
- removeTag,
117
- updateAutoCompleteOption,
118
- autoCompleteTimer,
119
- autoCompleteShow,
120
- reset,
121
- keyupFunction,
122
- isDuplicate,
123
- getDefaultTag
124
- }
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
+ const isMaxTagCountReached = computed(() => {
107
+ return props.maxTagCount > 0 ? tagAry.length >= props.maxTagCount : false
108
+ })
109
+
110
+ // 增加Tag
111
+ function addTag(event) {
112
+ // 檢查是否為中文輸入法組合狀態
113
+ if (event.isComposing || event.keyCode === 229) {
114
+ return
125
115
  }
116
+ if (newTag.value && !isDuplicate.value && !isMaxTagCountReached.value) {
117
+ tagAry.push(newTag.value)
118
+ }
119
+ newTag.value = ''
120
+ }
121
+ // 移除Tag
122
+ function removeTag(index) {
123
+ tagAry.splice(index, 1)
126
124
  }
125
+ function reset() {
126
+ tagAry.splice(0, tagAry.length)
127
+ newTag.value = ''
128
+ }
129
+
130
+ onMounted(() => {
131
+ getDefaultTag(props.defaultTagList)
132
+ })
133
+
134
+ defineExpose({
135
+ tagAry,
136
+ newTag,
137
+ addTag,
138
+ removeTag,
139
+ updateAutoCompleteOption,
140
+ autoCompleteTimer,
141
+ autoCompleteShow,
142
+ reset,
143
+ keyupFunction,
144
+ isDuplicate,
145
+ getDefaultTag,
146
+ isMaxTagCountReached
147
+ })
148
+ const emit = defineEmits(['update-auto-complete-option'])
149
+
127
150
  </script>
128
151
 
129
152
  <style lang="scss" scoped>
130
153
  .tag-editor {
131
- background: var(--bs-gray-100);
132
- border-radius: var(--bs-border-radius);
133
- padding: .5rem;
154
+ background: var(--bs-gray-100, #f9f9fd);
155
+ border-radius: var(--bs-border-radius-lg, 0.5rem);
156
+ padding: .75rem;
134
157
 
135
158
  .helper-text-box {
159
+ margin-top: .25rem;
136
160
  text-align: start;
137
161
 
138
162
  .helper-text {
139
- font-size: 0.75rem;
140
- color: var(--bs-gray-500);
163
+ line-height: 125%;
164
+ font-size: 0.875rem;
165
+ color: var(--bs-gray-500, #A9B3BD);
141
166
  }
142
167
  }
143
168
 
@@ -158,9 +183,9 @@ export default {
158
183
  position: absolute;
159
184
  top: calc(100% + 0.25rem);
160
185
  background: #fff;
161
- border: 1px solid var(--bs-gray-300);
162
- border-radius: var(--bs-border-radius);
163
- box-shadow: var(--bs-box-shadow);
186
+ border: 1px solid var(--bs-gray-300, #DBE2E7);
187
+ border-radius: var(--bs-border-radius, 0.375rem);
188
+ box-shadow: var(--bs-box-shadow, 0 0.5rem 1rem rgba(73, 85, 98, 0.15));
164
189
  }
165
190
 
166
191
  .opt-item {
@@ -180,7 +205,8 @@ export default {
180
205
  display: flex;
181
206
  align-items: center;
182
207
  flex-wrap: wrap;
183
- padding: .5rem .5rem .25rem .5rem;
208
+ gap: .25rem;
209
+ padding: .5rem;
184
210
 
185
211
  &.is-disabled:hover {
186
212
  cursor: not-allowed;
@@ -188,22 +214,41 @@ export default {
188
214
  }
189
215
 
190
216
  .new-tag-input {
217
+ height: 32px;
191
218
  all: unset;
192
219
  flex-grow: 1;
193
- margin-bottom: .25rem;
194
- background: var(--bs-gray-100);
220
+ background: var(--bs-gray-100, #f9f9fd);
195
221
  padding: .25rem .75rem;
196
222
  border-radius: 99px;
197
223
  border: 1px solid rgba(#000, 0);
224
+ transition: .2s ease-out;
225
+ border: 1px solid var(--bs-gray-200, #e8edf4);
226
+ outline-width: 3px;
227
+ outline-color: rgba(var(--purple-500-rgb, 100, 122, 241), 0);
228
+ outline-style: solid;
229
+
230
+ &::placeholder {
231
+ color: var(--bs-secondary-color, rgba(103, 120, 137, 0.5));
232
+ }
233
+
234
+ &:focus {
235
+ outline-width: 3px;
236
+ outline-color: rgba(var(--purple-500-rgb, 100, 122, 241), .25);
237
+ outline-style: solid;
238
+ }
198
239
  }
199
240
 
200
241
  .badge.rounded-pill {
201
- margin: 0 .25rem .25rem 0;
202
242
  display: inline-flex;
203
243
  align-items: stretch;
204
244
  overflow: hidden;
245
+ height: 32px;
246
+ padding: .5rem .75rem;
247
+ margin: 0;
205
248
 
206
249
  .tag-text {
250
+ font-size: .75rem;
251
+ font-weight: 500;
207
252
  margin: auto;
208
253
  overflow: hidden;
209
254
  text-overflow: ellipsis;
@@ -217,7 +262,7 @@ export default {
217
262
  display: block;
218
263
  content: ' ';
219
264
  height: 100%;
220
- border-left: 1px solid var(--bs-gray-300);
265
+ border-left: 1px solid var(--bs-gray-300, #DBE2E7);
221
266
  margin: 0 0.25rem;
222
267
  }
223
268
  }
@@ -231,7 +276,7 @@ export default {
231
276
  .material-icons {
232
277
  font-size: 16px;
233
278
  line-height: 16px;
234
- color: var(--bs-purple);
279
+ color: var(--bs-purple, #647AF1);
235
280
  opacity: .5;
236
281
  transition: .3s;
237
282
  }
@@ -245,6 +290,5 @@ export default {
245
290
  }
246
291
  }
247
292
  }
248
-
249
293
  }
250
294
  </style>