quasar-ui-sellmate-ui-kit 3.13.0 → 3.13.2

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