quasar-ui-sellmate-ui-kit 3.14.2 → 3.14.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.
@@ -1,360 +1,360 @@
1
- <template>
2
- <q-select
3
- outlined
4
- dense
5
- options-dense
6
- :dropdown-icon="selectDownArrowIcon"
7
- v-model="model"
8
- :options="filteredOptions"
9
- multiple
10
- emit-value
11
- map-options
12
- autocomplete="country"
13
- color="positive"
14
- :popup-content-class="['s-select-checkbox-opts', popupContentClass].join(' ')"
15
- class="s-select-checkbox"
16
- :option-label="optionLabel"
17
- :option-value="optionValue"
18
- :option-group="optionGroup"
19
- @add="onAddChecked"
20
- @remove="onRemoveChecked"
21
- :menu-offset="[0, 4]"
22
- menu-self="top left"
23
- menu-anchor="bottom start"
24
- no-error-icon
25
- hide-bottom-space
26
- ref="sSelectRef"
27
- >
28
- <!-- TODO: 아무것도 선택되지 않았을 때 props 값으로 표기 해줘야함 기본 값은 "전체" -->
29
- <template #before-options>
30
- <div class="search-input-form-container">
31
- <form class="select-search-input-form">
32
- <q-icon :name="searchIcon" size="20px" />
33
- <input
34
- v-model="search"
35
- autofocus
36
- class="select-search-input"
37
- :placeholder="searchPlaceholder"
38
- @input="
39
- data => {
40
- onSearch(data.target.value);
41
- }
42
- "
43
- />
44
- </form>
45
- </div>
46
- </template>
47
- <template #option="{ itemProps, opt, selected, toggleOption }">
48
- <q-item v-bind="itemProps" class="custom-select-options">
49
- <q-item-section side v-if="!opt.disable">
50
- <s-checkbox :modelValue="selected" @update:modelValue="toggleOption(opt)" />
51
- </q-item-section>
52
- <q-item-section v-if="opt[optionGroup]" class="text-Grey_Darken-4">
53
- {{ opt[optionGroup] }}
54
- </q-item-section>
55
- <q-item-section avatar v-if="opt.logo">
56
- <q-img class="q-pa-none bg-Grey_Lighten-5" :src="opt.logo" width="60px" height="22px" />
57
- </q-item-section>
58
- <q-item-section>
59
- {{ opt[optionLabel] }}
60
- </q-item-section>
61
- </q-item>
62
- </template>
63
- <template
64
- v-if="
65
- (options.length && useAll && (model[0] === '' || model.includes(''))) ||
66
- (noSelected && !options.length)
67
- "
68
- #selected
69
- >
70
- <div v-if="noSelected && !options.length">{{ noSelected }}</div>
71
- <div v-else-if="options.length && useAll && (model[0] === '' || model.includes(''))">
72
- {{ placeholder }}
73
- </div>
74
- </template>
75
- <template #no-option>
76
- <div class="search-input-form-container">
77
- <form class="select-search-input-form">
78
- <q-icon :name="searchIcon" size="20px" />
79
- <input
80
- v-model="search"
81
- autofocus
82
- class="select-search-input"
83
- :placeholder="searchPlaceholder"
84
- @input="
85
- data => {
86
- onSearch(data.target.value);
87
- }
88
- "
89
- />
90
- </form>
91
- </div>
92
- <q-item class="s-select-no-option">
93
- <q-item-section class="text-grey">{{ noData }}</q-item-section>
94
- </q-item>
95
- </template>
96
- </q-select>
97
- </template>
98
-
99
- <script>
100
- import { QIcon, QImg, QItem, QItemSection, QSelect, debounce } from 'quasar';
101
- import { defineComponent, nextTick, onBeforeMount, ref, watch } from 'vue';
102
- import { searchIcon, selectDownArrowIcon } from '../assets/icons';
103
-
104
- export default defineComponent({
105
- name: 'SSelectSearchCheckbox',
106
- emits: ['update:modelValue'],
107
- components: {
108
- QSelect,
109
- QItem,
110
- QItemSection,
111
- QImg,
112
- QIcon,
113
- },
114
- props: {
115
- searchPlaceholder: { type: String, default: '검색' },
116
- options: {
117
- type: Array,
118
- required: true,
119
- },
120
- modelValue: {
121
- type: Array,
122
- required: true,
123
- },
124
- optionLabel: {
125
- type: [String, Function],
126
- default: 'label',
127
- },
128
- optionValue: {
129
- type: String,
130
- default: 'value',
131
- },
132
- optionGroup: {
133
- type: String,
134
- default: 'group',
135
- },
136
- useAll: {
137
- type: Boolean,
138
- default: false,
139
- },
140
- placeholder: {
141
- type: String,
142
- default: '전체',
143
- },
144
- checkboxSearch: {
145
- type: String,
146
- default: '',
147
- },
148
- noData: {
149
- type: String,
150
- default: '데이터 없음',
151
- },
152
- popupContentClass: {
153
- type: String,
154
- },
155
- noSelected: {
156
- type: String,
157
- default: '선택',
158
- },
159
- },
160
- setup(props, { emit }) {
161
- const model = ref(props.modelValue);
162
- const filteredOptions = ref(props.options);
163
- const searchInput = ref(null);
164
- const search = ref('');
165
- const isDisable = props.options.find(v => Boolean(v.disable));
166
-
167
- /**
168
- * @param {{ index: number; value: string | number }} detail
169
- */
170
- function onRemoveChecked(detail) {
171
- const idx = model.value.findIndex(v => v === '');
172
- if (detail.value === '') {
173
- nextTick(() => {
174
- model.value = [];
175
- });
176
- } else if (idx >= 0) {
177
- nextTick(() => {
178
- model.value.splice(idx, 1);
179
- });
180
- }
181
- }
182
-
183
- /**
184
- * @param {{ index: number; value: string | number }} detail
185
- */
186
- function onAddChecked(detail) {
187
- if (detail.value === '') {
188
- nextTick(() => {
189
- model.value = props.options
190
- .filter(v => !v.category)
191
- .map(option => option[props.optionValue]);
192
- });
193
- } else {
194
- nextTick(() => {
195
- if (model.value.length === props.options.length - 1) {
196
- model.value = props.options
197
- .filter(v => !v.category)
198
- .map(option => option[props.optionValue]);
199
- }
200
- });
201
- }
202
- }
203
-
204
- const onSearch = debounce(val => {
205
- if (val === '') {
206
- filteredOptions.value = props.options;
207
- } else {
208
- filteredOptions.value = props.options.filter(
209
- v => (v[props.optionLabel] || v).toLowerCase().indexOf(val.toLowerCase()) > -1,
210
- );
211
- }
212
- }, 200);
213
-
214
- watch(
215
- () => props.modelValue,
216
- val => {
217
- model.value = val;
218
-
219
- if (
220
- props.options.filter(opt => opt[props.optionValue] && !opt.category).length ===
221
- model.value.length &&
222
- model.value.length
223
- ) {
224
- model.value = props.options
225
- .filter(v => !v.category)
226
- .map(option => option[props.optionValue]);
227
- }
228
- },
229
- );
230
-
231
- watch(model, val => {
232
- emit('update:modelValue', val);
233
- });
234
-
235
- const allSelectedModel = () => {
236
- if (props.useAll && model.value.filter(v => v).length < 1) {
237
- model.value = props.options
238
- .filter(v => !v[props.optionGroup])
239
- .map(option => option[props.optionValue]);
240
- }
241
- };
242
-
243
- watch(
244
- () => props.options,
245
- val => {
246
- model.value = [];
247
- filteredOptions.value = val;
248
- nextTick(() => {
249
- allSelectedModel();
250
- });
251
- },
252
- );
253
-
254
- onBeforeMount(() => {
255
- allSelectedModel();
256
- });
257
-
258
- return {
259
- model,
260
- selectDownArrowIcon,
261
- onRemoveChecked,
262
- onAddChecked,
263
- onSearch,
264
- isDisable,
265
- filteredOptions,
266
- search,
267
- searchInput,
268
- searchIcon,
269
- sSelectRef: ref(null),
270
- };
271
- },
272
- });
273
- </script>
274
-
275
- <style lang="scss">
276
- @import '../css/quasar.variables.scss';
277
- @import '../css/extends.scss';
278
-
279
- .s-select-checkbox {
280
- @extend %select;
281
-
282
- .q-field__native {
283
- display: block;
284
- min-height: 0;
285
- height: $default-height;
286
- width: 100%;
287
- padding: $select-padding !important;
288
- color: $Grey_Darken-4;
289
- white-space: nowrap;
290
- overflow: hidden;
291
- text-overflow: ellipsis;
292
-
293
- > span {
294
- max-height: $default-height;
295
- }
296
-
297
- > .s-checkbox {
298
- margin-right: $default-icon-margin;
299
- }
300
- }
301
- }
302
-
303
- .s-select-checkbox-opts {
304
- @extend %select-menu-list;
305
- }
306
-
307
- .custom-select-options {
308
- height: $default-height;
309
- }
310
-
311
- .disabled.s-select-checkbox-option {
312
- border: none;
313
- background: none !important;
314
- color: $Grey_Default !important;
315
- }
316
-
317
- .select-search-input-form {
318
- height: 28px;
319
- display: flex;
320
- align-items: center;
321
- padding-left: 8px;
322
- position: relative;
323
- border-radius: 2px;
324
- border: 1px solid $Grey_Lighten-1;
325
- background-color: white;
326
- position: sticky;
327
- top: 0;
328
- z-index: 1;
329
- margin: 4px;
330
-
331
- &::after {
332
- content: '';
333
- position: absolute;
334
- top: 0;
335
- right: 0;
336
- bottom: 0;
337
- left: 0;
338
- pointer-events: none;
339
- border: 1px solid transparent;
340
- border-radius: inherit;
341
- }
342
-
343
- &:hover,
344
- &:focus-within {
345
- &::after {
346
- border-color: #0075ff;
347
- box-shadow: 0 0 4px #0075ff;
348
- transition: border-color 0.36s cubic-bezier(0.4, 0, 0.2, 1);
349
- }
350
- }
351
-
352
- .select-search-input {
353
- font-size: 12px;
354
- margin-left: 8px;
355
- flex-grow: 1;
356
- border: none;
357
- outline: none;
358
- }
359
- }
360
- </style>
1
+ <template>
2
+ <q-select
3
+ outlined
4
+ dense
5
+ options-dense
6
+ :dropdown-icon="selectDownArrowIcon"
7
+ v-model="model"
8
+ :options="filteredOptions"
9
+ multiple
10
+ emit-value
11
+ map-options
12
+ autocomplete="country"
13
+ color="positive"
14
+ :popup-content-class="['s-select-checkbox-opts', popupContentClass].join(' ')"
15
+ class="s-select-checkbox"
16
+ :option-label="optionLabel"
17
+ :option-value="optionValue"
18
+ :option-group="optionGroup"
19
+ @add="onAddChecked"
20
+ @remove="onRemoveChecked"
21
+ :menu-offset="[0, 4]"
22
+ menu-self="top left"
23
+ menu-anchor="bottom start"
24
+ no-error-icon
25
+ hide-bottom-space
26
+ ref="sSelectRef"
27
+ >
28
+ <!-- TODO: 아무것도 선택되지 않았을 때 props 값으로 표기 해줘야함 기본 값은 "전체" -->
29
+ <template #before-options>
30
+ <div class="search-input-form-container">
31
+ <form class="select-search-input-form">
32
+ <q-icon :name="searchIcon" size="20px" />
33
+ <input
34
+ v-model="search"
35
+ autofocus
36
+ class="select-search-input"
37
+ :placeholder="searchPlaceholder"
38
+ @input="
39
+ data => {
40
+ onSearch(data.target.value);
41
+ }
42
+ "
43
+ />
44
+ </form>
45
+ </div>
46
+ </template>
47
+ <template #option="{ itemProps, opt, selected, toggleOption }">
48
+ <q-item v-bind="itemProps" class="custom-select-options">
49
+ <q-item-section side v-if="!opt.disable">
50
+ <s-checkbox :modelValue="selected" @update:modelValue="toggleOption(opt)" />
51
+ </q-item-section>
52
+ <q-item-section v-if="opt[optionGroup]" class="text-Grey_Darken-4">
53
+ {{ opt[optionGroup] }}
54
+ </q-item-section>
55
+ <q-item-section avatar v-if="opt.logo">
56
+ <q-img class="q-pa-none bg-Grey_Lighten-5" :src="opt.logo" width="60px" height="22px" />
57
+ </q-item-section>
58
+ <q-item-section>
59
+ {{ opt[optionLabel] }}
60
+ </q-item-section>
61
+ </q-item>
62
+ </template>
63
+ <template
64
+ v-if="
65
+ (options.length && useAll && (model[0] === '' || model.includes(''))) ||
66
+ (noSelected && !options.length)
67
+ "
68
+ #selected
69
+ >
70
+ <div v-if="noSelected && !options.length">{{ noSelected }}</div>
71
+ <div v-else-if="options.length && useAll && (model[0] === '' || model.includes(''))">
72
+ {{ placeholder }}
73
+ </div>
74
+ </template>
75
+ <template #no-option>
76
+ <div class="search-input-form-container">
77
+ <form class="select-search-input-form">
78
+ <q-icon :name="searchIcon" size="20px" />
79
+ <input
80
+ v-model="search"
81
+ autofocus
82
+ class="select-search-input"
83
+ :placeholder="searchPlaceholder"
84
+ @input="
85
+ data => {
86
+ onSearch(data.target.value);
87
+ }
88
+ "
89
+ />
90
+ </form>
91
+ </div>
92
+ <q-item class="s-select-no-option">
93
+ <q-item-section class="text-grey">{{ noData }}</q-item-section>
94
+ </q-item>
95
+ </template>
96
+ </q-select>
97
+ </template>
98
+
99
+ <script>
100
+ import { QIcon, QImg, QItem, QItemSection, QSelect, debounce } from 'quasar';
101
+ import { defineComponent, nextTick, onBeforeMount, ref, watch } from 'vue';
102
+ import { searchIcon, selectDownArrowIcon } from '../assets/icons';
103
+
104
+ export default defineComponent({
105
+ name: 'SSelectSearchCheckbox',
106
+ emits: ['update:modelValue'],
107
+ components: {
108
+ QSelect,
109
+ QItem,
110
+ QItemSection,
111
+ QImg,
112
+ QIcon,
113
+ },
114
+ props: {
115
+ searchPlaceholder: { type: String, default: '검색' },
116
+ options: {
117
+ type: Array,
118
+ required: true,
119
+ },
120
+ modelValue: {
121
+ type: Array,
122
+ required: true,
123
+ },
124
+ optionLabel: {
125
+ type: [String, Function],
126
+ default: 'label',
127
+ },
128
+ optionValue: {
129
+ type: String,
130
+ default: 'value',
131
+ },
132
+ optionGroup: {
133
+ type: String,
134
+ default: 'group',
135
+ },
136
+ useAll: {
137
+ type: Boolean,
138
+ default: false,
139
+ },
140
+ placeholder: {
141
+ type: String,
142
+ default: '전체',
143
+ },
144
+ checkboxSearch: {
145
+ type: String,
146
+ default: '',
147
+ },
148
+ noData: {
149
+ type: String,
150
+ default: '데이터 없음',
151
+ },
152
+ popupContentClass: {
153
+ type: String,
154
+ },
155
+ noSelected: {
156
+ type: String,
157
+ default: '선택',
158
+ },
159
+ },
160
+ setup(props, { emit }) {
161
+ const model = ref(props.modelValue);
162
+ const filteredOptions = ref(props.options);
163
+ const searchInput = ref(null);
164
+ const search = ref('');
165
+ const isDisable = props.options.find(v => Boolean(v.disable));
166
+
167
+ /**
168
+ * @param {{ index: number; value: string | number }} detail
169
+ */
170
+ function onRemoveChecked(detail) {
171
+ const idx = model.value.findIndex(v => v === '');
172
+ if (detail.value === '') {
173
+ nextTick(() => {
174
+ model.value = [];
175
+ });
176
+ } else if (idx >= 0) {
177
+ nextTick(() => {
178
+ model.value.splice(idx, 1);
179
+ });
180
+ }
181
+ }
182
+
183
+ /**
184
+ * @param {{ index: number; value: string | number }} detail
185
+ */
186
+ function onAddChecked(detail) {
187
+ if (detail.value === '') {
188
+ nextTick(() => {
189
+ model.value = props.options
190
+ .filter(v => !v.category)
191
+ .map(option => option[props.optionValue]);
192
+ });
193
+ } else {
194
+ nextTick(() => {
195
+ if (model.value.length === props.options.length - 1) {
196
+ model.value = props.options
197
+ .filter(v => !v.category)
198
+ .map(option => option[props.optionValue]);
199
+ }
200
+ });
201
+ }
202
+ }
203
+
204
+ const onSearch = debounce(val => {
205
+ if (val === '') {
206
+ filteredOptions.value = props.options;
207
+ } else {
208
+ filteredOptions.value = props.options.filter(
209
+ v => (v[props.optionLabel] || v).toLowerCase().indexOf(val.toLowerCase()) > -1,
210
+ );
211
+ }
212
+ }, 200);
213
+
214
+ watch(
215
+ () => props.modelValue,
216
+ val => {
217
+ model.value = val;
218
+
219
+ if (
220
+ props.options.filter(opt => opt[props.optionValue] && !opt.category).length ===
221
+ model.value.length &&
222
+ model.value.length
223
+ ) {
224
+ model.value = props.options
225
+ .filter(v => !v.category)
226
+ .map(option => option[props.optionValue]);
227
+ }
228
+ },
229
+ );
230
+
231
+ watch(model, val => {
232
+ emit('update:modelValue', val);
233
+ });
234
+
235
+ const allSelectedModel = () => {
236
+ if (props.useAll && model.value.filter(v => v).length < 1) {
237
+ model.value = props.options
238
+ .filter(v => !v[props.optionGroup])
239
+ .map(option => option[props.optionValue]);
240
+ }
241
+ };
242
+
243
+ watch(
244
+ () => props.options,
245
+ val => {
246
+ model.value = [];
247
+ filteredOptions.value = val;
248
+ nextTick(() => {
249
+ allSelectedModel();
250
+ });
251
+ },
252
+ );
253
+
254
+ onBeforeMount(() => {
255
+ allSelectedModel();
256
+ });
257
+
258
+ return {
259
+ model,
260
+ selectDownArrowIcon,
261
+ onRemoveChecked,
262
+ onAddChecked,
263
+ onSearch,
264
+ isDisable,
265
+ filteredOptions,
266
+ search,
267
+ searchInput,
268
+ searchIcon,
269
+ sSelectRef: ref(null),
270
+ };
271
+ },
272
+ });
273
+ </script>
274
+
275
+ <style lang="scss">
276
+ @import '../css/quasar.variables.scss';
277
+ @import '../css/extends.scss';
278
+
279
+ .s-select-checkbox {
280
+ @extend %select;
281
+
282
+ .q-field__native {
283
+ display: block;
284
+ min-height: 0;
285
+ height: $default-height;
286
+ width: 100%;
287
+ padding: $select-padding !important;
288
+ color: $Grey_Darken-4;
289
+ white-space: nowrap;
290
+ overflow: hidden;
291
+ text-overflow: ellipsis;
292
+
293
+ > span {
294
+ max-height: $default-height;
295
+ }
296
+
297
+ > .s-checkbox {
298
+ margin-right: $default-icon-margin;
299
+ }
300
+ }
301
+ }
302
+
303
+ .s-select-checkbox-opts {
304
+ @extend %select-menu-list;
305
+ }
306
+
307
+ .custom-select-options {
308
+ height: $default-height;
309
+ }
310
+
311
+ .disabled.s-select-checkbox-option {
312
+ border: none;
313
+ background: none !important;
314
+ color: $Grey_Default !important;
315
+ }
316
+
317
+ .select-search-input-form {
318
+ height: 28px;
319
+ display: flex;
320
+ align-items: center;
321
+ padding-left: 8px;
322
+ position: relative;
323
+ border-radius: 2px;
324
+ border: 1px solid $Grey_Lighten-1;
325
+ background-color: white;
326
+ position: sticky;
327
+ top: 0;
328
+ z-index: 1;
329
+ margin: 4px;
330
+
331
+ &::after {
332
+ content: '';
333
+ position: absolute;
334
+ top: 0;
335
+ right: 0;
336
+ bottom: 0;
337
+ left: 0;
338
+ pointer-events: none;
339
+ border: 1px solid transparent;
340
+ border-radius: inherit;
341
+ }
342
+
343
+ &:hover,
344
+ &:focus-within {
345
+ &::after {
346
+ border-color: #0075ff;
347
+ box-shadow: 0 0 4px #0075ff;
348
+ transition: border-color 0.36s cubic-bezier(0.4, 0, 0.2, 1);
349
+ }
350
+ }
351
+
352
+ .select-search-input {
353
+ font-size: 12px;
354
+ margin-left: 8px;
355
+ flex-grow: 1;
356
+ border: none;
357
+ outline: none;
358
+ }
359
+ }
360
+ </style>