@volverjs/ui-vue 0.0.5-beta.2 → 0.0.5-beta.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.
Files changed (32) hide show
  1. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.es.js +7 -1
  2. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.umd.js +1 -1
  3. package/dist/components/VvCombobox/VvCombobox.es.js +171 -64
  4. package/dist/components/VvCombobox/VvCombobox.umd.js +1 -1
  5. package/dist/components/VvCombobox/VvCombobox.vue.d.ts +0 -8
  6. package/dist/components/VvDropdown/VvDropdownOptgroup.vue.d.ts +6 -0
  7. package/dist/components/VvDropdownOptgroup/VvDropdownOptgroup.es.js +237 -0
  8. package/dist/components/VvDropdownOptgroup/VvDropdownOptgroup.umd.js +1 -0
  9. package/dist/components/VvRadioGroup/VvRadioGroup.es.js +7 -1
  10. package/dist/components/VvRadioGroup/VvRadioGroup.umd.js +1 -1
  11. package/dist/components/VvSelect/VvSelect.es.js +42 -10
  12. package/dist/components/VvSelect/VvSelect.umd.js +1 -1
  13. package/dist/components/VvSelect/VvSelect.vue.d.ts +4 -3
  14. package/dist/components/index.es.js +241 -134
  15. package/dist/components/index.umd.js +1 -1
  16. package/dist/composables/useOptions.d.ts +1 -0
  17. package/dist/icons.es.js +3 -3
  18. package/dist/icons.umd.js +1 -1
  19. package/dist/resolvers/unplugin.es.js +2 -1
  20. package/dist/resolvers/unplugin.umd.js +1 -1
  21. package/package.json +9 -1
  22. package/src/assets/icons/detailed.json +1 -1
  23. package/src/assets/icons/normal.json +1 -1
  24. package/src/assets/icons/simple.json +1 -1
  25. package/src/components/VvCombobox/VvCombobox.vue +95 -28
  26. package/src/components/VvDropdown/VvDropdownOptgroup.vue +18 -0
  27. package/src/components/VvSelect/VvSelect.vue +38 -10
  28. package/src/composables/useOptions.ts +6 -0
  29. package/src/resolvers/unplugin.ts +2 -1
  30. package/src/stories/Combobox/ComboboxOptions.stories.mdx +35 -0
  31. package/src/stories/Select/SelectOptions.stories.mdx +35 -0
  32. package/src/types/generic.d.ts +2 -1
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  export default {
3
3
  name: 'VvCombobox',
4
- components: { VvDropdown, VvDropdownOption },
4
+ components: { VvDropdown, VvDropdownOption, VvDropdownOptgroup },
5
5
  }
6
6
  </script>
7
7
 
@@ -11,6 +11,7 @@
11
11
  import VvIcon from '../VvIcon/VvIcon.vue'
12
12
  import VvDropdown from '../VvDropdown/VvDropdown.vue'
13
13
  import VvDropdownOption from '../VvDropdown/VvDropdownOption.vue'
14
+ import VvDropdownOptgroup from '../VvDropdown/VvDropdownOptgroup.vue'
14
15
  import VvSelect from '../VvSelect/VvSelect.vue'
15
16
  import VvBadge from '../VvBadge/VvBadge.vue'
16
17
  import HintSlotFactory from '../common/HintSlot'
@@ -29,6 +30,14 @@
29
30
  props,
30
31
  )
31
32
 
33
+ // Grouped options
34
+ const isGroup = (option: string | Option) => {
35
+ if (typeof option === 'string') {
36
+ return false
37
+ }
38
+ return option.options && option.options.length > 0
39
+ }
40
+
32
41
  // hint slot
33
42
  const { HintSlot } = HintSlotFactory(props, slots)
34
43
 
@@ -155,8 +164,12 @@
155
164
  props.searchable ? filteredOptions.value : props.options,
156
165
  )
157
166
 
158
- const { getOptionLabel, getOptionValue, getOptionDisabled } =
159
- useOptions(props)
167
+ const {
168
+ getOptionLabel,
169
+ getOptionValue,
170
+ getOptionDisabled,
171
+ getOptionGrouped,
172
+ } = useOptions(props)
160
173
 
161
174
  // options filtered by search text
162
175
  const filteredOptions = computed(() => {
@@ -197,9 +210,21 @@
197
210
  } else if (props.modelValue) {
198
211
  selectedValues = [props.modelValue]
199
212
  }
200
- return props.options.filter((option) =>
201
- selectedValues.includes(getOptionValue(option)),
202
- )
213
+ const options = props.options.reduce((acc, value) => {
214
+ if (isGroup(value)) {
215
+ return [...acc, ...getOptionGrouped(value)]
216
+ }
217
+ return [...acc, value]
218
+ }, [] as Array<Option | string>)
219
+
220
+ return options.filter((option) => {
221
+ if (isGroup(option)) {
222
+ return getOptionGrouped(option).some((item) =>
223
+ selectedValues.includes(getOptionValue(item)),
224
+ )
225
+ }
226
+ return selectedValues.includes(getOptionValue(option))
227
+ })
203
228
  })
204
229
 
205
230
  const hasValue = computed(() => {
@@ -439,35 +464,77 @@
439
464
  </template>
440
465
  <template #items>
441
466
  <template v-if="filteredOptions.length">
442
- <VvDropdownOption
467
+ <template
443
468
  v-for="(option, index) in filteredOptions"
444
- v-bind="{
445
- disabled: getOptionDisabled(option),
446
- selected: getOptionSelected(option),
447
- unselectable,
448
- deselectHintLabel:
449
- propsDefaults.deselectHintLabel,
450
- selectHintLabel: propsDefaults.selectHintLabel,
451
- selectedHintLabel:
452
- propsDefaults.selectedHintLabel,
453
- }"
454
469
  :key="index"
455
- class="vv-dropdown-option"
456
- @click.passive="onInput(option)"
457
470
  >
458
- <!-- @slot Slot for option customization -->
459
- <slot
460
- name="option"
471
+ <template v-if="isGroup(option)">
472
+ <VvDropdownOptgroup
473
+ :label="getOptionLabel(option)"
474
+ />
475
+ <VvDropdownOption
476
+ v-for="(item, i) in getOptionGrouped(
477
+ option,
478
+ )"
479
+ v-bind="{
480
+ disabled: getOptionDisabled(item),
481
+ selected: getOptionSelected(item),
482
+ unselectable,
483
+ deselectHintLabel:
484
+ propsDefaults.deselectHintLabel,
485
+ selectHintLabel:
486
+ propsDefaults.selectHintLabel,
487
+ selectedHintLabel:
488
+ propsDefaults.selectedHintLabel,
489
+ }"
490
+ :key="i"
491
+ class="vv-dropdown-option"
492
+ @click.passive="onInput(item)"
493
+ >
494
+ <!-- @slot Slot for option customization -->
495
+ <slot
496
+ name="option"
497
+ v-bind="{
498
+ option,
499
+ selectedOptions,
500
+ selected: getOptionSelected(item),
501
+ disabled: getOptionDisabled(item),
502
+ }"
503
+ >
504
+ {{ getOptionLabel(item) }}
505
+ </slot>
506
+ </VvDropdownOption>
507
+ </template>
508
+ <VvDropdownOption
509
+ v-else
461
510
  v-bind="{
462
- option,
463
- selectedOptions,
464
- selected: getOptionSelected(option),
465
511
  disabled: getOptionDisabled(option),
512
+ selected: getOptionSelected(option),
513
+ unselectable,
514
+ deselectHintLabel:
515
+ propsDefaults.deselectHintLabel,
516
+ selectHintLabel:
517
+ propsDefaults.selectHintLabel,
518
+ selectedHintLabel:
519
+ propsDefaults.selectedHintLabel,
466
520
  }"
521
+ class="vv-dropdown-option"
522
+ @click.passive="onInput(option)"
467
523
  >
468
- {{ getOptionLabel(option) }}
469
- </slot>
470
- </VvDropdownOption>
524
+ <!-- @slot Slot for option customization -->
525
+ <slot
526
+ name="option"
527
+ v-bind="{
528
+ option,
529
+ selectedOptions,
530
+ selected: getOptionSelected(option),
531
+ disabled: getOptionDisabled(option),
532
+ }"
533
+ >
534
+ {{ getOptionLabel(option) }}
535
+ </slot>
536
+ </VvDropdownOption>
537
+ </template>
471
538
  </template>
472
539
  <VvDropdownOption
473
540
  v-else-if="!options.length"
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ export default {
3
+ name: 'VvDropdownOptgroup',
4
+ }
5
+ </script>
6
+
7
+ <script setup lang="ts">
8
+ import { LabelProps } from '../../props'
9
+ const props = defineProps({
10
+ ...LabelProps,
11
+ })
12
+ </script>
13
+
14
+ <template>
15
+ <li class="vv-dropdown-optgroup" role="presentation" tabindex="-1">
16
+ {{ props.label }}
17
+ </li>
18
+ </template>
@@ -9,6 +9,7 @@
9
9
  import VvIcon from '../VvIcon/VvIcon.vue'
10
10
  import HintSlotFactory from '../common/HintSlot'
11
11
  import { VvSelectProps, VvSelectEmits } from '.'
12
+ import type { Option } from '@/types/generic'
12
13
 
13
14
  // props, emit and slots
14
15
  const props = defineProps(VvSelectProps)
@@ -124,8 +125,12 @@
124
125
  modelValue: props.modelValue,
125
126
  }))
126
127
 
127
- const { getOptionLabel, getOptionValue, getOptionDisabled } =
128
- useOptions(props)
128
+ const {
129
+ getOptionLabel,
130
+ getOptionValue,
131
+ getOptionDisabled,
132
+ getOptionGrouped,
133
+ } = useOptions(props)
129
134
 
130
135
  const localModelValue = computed({
131
136
  get: () => {
@@ -138,6 +143,12 @@
138
143
  emit('update:modelValue', newValue)
139
144
  },
140
145
  })
146
+
147
+ // Grouped options
148
+ const isGroup = (option: string | Option) => {
149
+ if (typeof option === 'string') return false
150
+ return option && option.options && option.options.length > 0
151
+ }
141
152
  </script>
142
153
 
143
154
  <template>
@@ -169,14 +180,31 @@
169
180
  >
170
181
  {{ placeholder }}
171
182
  </option>
172
- <option
173
- v-for="(option, index) in options"
174
- :key="index"
175
- :disabled="getOptionDisabled(option)"
176
- :value="getOptionValue(option)"
177
- >
178
- {{ getOptionLabel(option) }}
179
- </option>
183
+ <template v-for="(option, index) in options">
184
+ <option
185
+ v-if="!isGroup(option)"
186
+ :key="index"
187
+ :disabled="getOptionDisabled(option)"
188
+ :value="getOptionValue(option)"
189
+ >
190
+ {{ getOptionLabel(option) }}
191
+ </option>
192
+ <optgroup
193
+ v-else
194
+ :key="`group-${index}`"
195
+ :disabled="getOptionDisabled(option)"
196
+ :label="getOptionLabel(option)"
197
+ >
198
+ <option
199
+ v-for="(item, i) in getOptionGrouped(option)"
200
+ :key="`group-${index}-item-${i}`"
201
+ :disabled="getOptionDisabled(item)"
202
+ :value="getOptionValue(item)"
203
+ >
204
+ {{ getOptionLabel(item) }}
205
+ </option>
206
+ </optgroup>
207
+ </template>
180
208
  </select>
181
209
  <VvIcon
182
210
  v-if="hasIconAfter"
@@ -29,10 +29,16 @@ export function useOptions(props: any) {
29
29
  : option[disabledKey.value]
30
30
  }
31
31
 
32
+ const getOptionGrouped = (option: string | Option) => {
33
+ if (typeof option !== 'object' && option !== null) return []
34
+ return option.options || []
35
+ }
36
+
32
37
  return {
33
38
  options,
34
39
  getOptionLabel,
35
40
  getOptionValue,
36
41
  getOptionDisabled,
42
+ getOptionGrouped
37
43
  }
38
44
  }
@@ -54,8 +54,9 @@ export const getStyleNames = function (kebabName: string) {
54
54
  if (kebabName === 'vv-combobox') {
55
55
  return [
56
56
  'vv-select',
57
- 'vv-dropdown',
58
57
  'vv-dropdown-option',
58
+ 'vv-dropdown-optgroup',
59
+ 'vv-dropdown',
59
60
  'vv-dropdown-action',
60
61
  ]
61
62
  }
@@ -98,3 +98,38 @@ import { defaultTest } from './Combobox.test'
98
98
  {Template.bind()}
99
99
  </Story>
100
100
  </Canvas>
101
+
102
+ <Canvas>
103
+ <Story
104
+ name="Grouped options"
105
+ play={defaultTest}
106
+ argTypes={{
107
+ options: {
108
+ ...argTypes.options,
109
+ control: {
110
+ disable: true,
111
+ },
112
+ },
113
+ }}
114
+ args={{
115
+ options: [
116
+ {
117
+ label: 'Group 1',
118
+ options: [
119
+ { value: 'first', label: 'First' },
120
+ { value: 'second', label: 'Second' },
121
+ ],
122
+ },
123
+ {
124
+ label: 'Group 2',
125
+ options: [
126
+ { value: 'third', label: 'Third' },
127
+ { value: 'fourth', label: 'Fourth' },
128
+ ],
129
+ },
130
+ ],
131
+ }}
132
+ >
133
+ {Template.bind()}
134
+ </Story>
135
+ </Canvas>
@@ -98,3 +98,38 @@ import { defaultTest } from './Select.test'
98
98
  {Template.bind()}
99
99
  </Story>
100
100
  </Canvas>
101
+
102
+ <Canvas>
103
+ <Story
104
+ name="Grouped options"
105
+ play={defaultTest}
106
+ argTypes={{
107
+ options: {
108
+ ...argTypes.options,
109
+ control: {
110
+ disable: true,
111
+ },
112
+ },
113
+ }}
114
+ args={{
115
+ options: [
116
+ {
117
+ label: 'Group 1',
118
+ options: [
119
+ { value: 'first', label: 'First' },
120
+ { value: 'second', label: 'Second' },
121
+ ]
122
+ },
123
+ {
124
+ label: 'Group 2',
125
+ options: [
126
+ { value: 'third', label: 'Third' },
127
+ { value: 'fourth', label: 'Fourth' },
128
+ ]
129
+ },
130
+ ],
131
+ }}
132
+ >
133
+ {Template.bind()}
134
+ </Story>
135
+ </Canvas>
@@ -1,5 +1,6 @@
1
1
  export type Nullable<T> = T | null | undefined
2
2
 
3
3
  export type Option = {
4
- [key: string]: unknown
4
+ options?: Option[],
5
+ [key: string]: unknown,
5
6
  }