jobdone-shared-files 1.1.11 → 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 -116
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jobdone-shared-files",
3
- "version": "1.1.11",
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,135 +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($event)" @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(event) {
95
- // 檢查是否為中文輸入法組合狀態
96
- if (event.isComposing || event.keyCode === 229) {
97
- return
98
- }
99
- if (newTag.value && !isDuplicate.value) {
100
- tagAry.push(newTag.value)
101
- }
102
- newTag.value = ''
103
- }
104
- // 移除Tag
105
- function removeTag(index) {
106
- tagAry.splice(index, 1)
107
- }
108
- function reset() {
109
- tagAry.splice(0, tagAry.length)
110
- newTag.value = ''
111
- }
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
+ }
112
90
 
113
- onMounted(() => {
114
- getDefaultTag(props.defaultTagList)
115
- })
116
- return {
117
- tagAry,
118
- newTag,
119
- addTag,
120
- removeTag,
121
- updateAutoCompleteOption,
122
- autoCompleteTimer,
123
- autoCompleteShow,
124
- reset,
125
- keyupFunction,
126
- isDuplicate,
127
- getDefaultTag
128
- }
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
115
+ }
116
+ if (newTag.value && !isDuplicate.value && !isMaxTagCountReached.value) {
117
+ tagAry.push(newTag.value)
129
118
  }
119
+ newTag.value = ''
130
120
  }
121
+ // 移除Tag
122
+ function removeTag(index) {
123
+ tagAry.splice(index, 1)
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
+
131
150
  </script>
132
151
 
133
152
  <style lang="scss" scoped>
134
153
  .tag-editor {
135
- background: var(--bs-gray-100);
136
- border-radius: var(--bs-border-radius);
137
- padding: .5rem;
154
+ background: var(--bs-gray-100, #f9f9fd);
155
+ border-radius: var(--bs-border-radius-lg, 0.5rem);
156
+ padding: .75rem;
138
157
 
139
158
  .helper-text-box {
159
+ margin-top: .25rem;
140
160
  text-align: start;
141
161
 
142
162
  .helper-text {
143
- font-size: 0.75rem;
144
- color: var(--bs-gray-500);
163
+ line-height: 125%;
164
+ font-size: 0.875rem;
165
+ color: var(--bs-gray-500, #A9B3BD);
145
166
  }
146
167
  }
147
168
 
@@ -162,9 +183,9 @@ export default {
162
183
  position: absolute;
163
184
  top: calc(100% + 0.25rem);
164
185
  background: #fff;
165
- border: 1px solid var(--bs-gray-300);
166
- border-radius: var(--bs-border-radius);
167
- 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));
168
189
  }
169
190
 
170
191
  .opt-item {
@@ -184,7 +205,8 @@ export default {
184
205
  display: flex;
185
206
  align-items: center;
186
207
  flex-wrap: wrap;
187
- padding: .5rem .5rem .25rem .5rem;
208
+ gap: .25rem;
209
+ padding: .5rem;
188
210
 
189
211
  &.is-disabled:hover {
190
212
  cursor: not-allowed;
@@ -192,22 +214,41 @@ export default {
192
214
  }
193
215
 
194
216
  .new-tag-input {
217
+ height: 32px;
195
218
  all: unset;
196
219
  flex-grow: 1;
197
- margin-bottom: .25rem;
198
- background: var(--bs-gray-100);
220
+ background: var(--bs-gray-100, #f9f9fd);
199
221
  padding: .25rem .75rem;
200
222
  border-radius: 99px;
201
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
+ }
202
239
  }
203
240
 
204
241
  .badge.rounded-pill {
205
- margin: 0 .25rem .25rem 0;
206
242
  display: inline-flex;
207
243
  align-items: stretch;
208
244
  overflow: hidden;
245
+ height: 32px;
246
+ padding: .5rem .75rem;
247
+ margin: 0;
209
248
 
210
249
  .tag-text {
250
+ font-size: .75rem;
251
+ font-weight: 500;
211
252
  margin: auto;
212
253
  overflow: hidden;
213
254
  text-overflow: ellipsis;
@@ -221,7 +262,7 @@ export default {
221
262
  display: block;
222
263
  content: ' ';
223
264
  height: 100%;
224
- border-left: 1px solid var(--bs-gray-300);
265
+ border-left: 1px solid var(--bs-gray-300, #DBE2E7);
225
266
  margin: 0 0.25rem;
226
267
  }
227
268
  }
@@ -235,7 +276,7 @@ export default {
235
276
  .material-icons {
236
277
  font-size: 16px;
237
278
  line-height: 16px;
238
- color: var(--bs-purple);
279
+ color: var(--bs-purple, #647AF1);
239
280
  opacity: .5;
240
281
  transition: .3s;
241
282
  }
@@ -249,6 +290,5 @@ export default {
249
290
  }
250
291
  }
251
292
  }
252
-
253
293
  }
254
294
  </style>