@volverjs/ui-vue 0.0.5-beta.1 → 0.0.5-beta.3

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 (77) hide show
  1. package/dist/components/VvAction/VvAction.es.js +10 -0
  2. package/dist/components/VvBadge/VvBadge.es.js +10 -0
  3. package/dist/components/VvBreadcrumb/VvBreadcrumb.es.js +10 -0
  4. package/dist/components/VvButton/VvButton.es.js +10 -0
  5. package/dist/components/VvButtonGroup/VvButtonGroup.es.js +10 -0
  6. package/dist/components/VvCheckbox/VvCheckbox.es.js +10 -0
  7. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.es.js +17 -1
  8. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.umd.js +1 -1
  9. package/dist/components/VvCombobox/VvCombobox.es.js +174 -64
  10. package/dist/components/VvCombobox/VvCombobox.umd.js +1 -1
  11. package/dist/components/VvCombobox/VvCombobox.vue.d.ts +16 -11
  12. package/dist/components/VvCombobox/index.d.ts +6 -1
  13. package/dist/components/VvDialog/VvDialog.es.js +10 -0
  14. package/dist/components/VvDropdown/VvDropdown.es.js +14 -2
  15. package/dist/components/VvDropdown/VvDropdown.umd.js +1 -1
  16. package/dist/components/VvDropdown/VvDropdown.vue.d.ts +27 -11
  17. package/dist/components/VvDropdown/VvDropdownOptgroup.vue.d.ts +6 -0
  18. package/dist/components/VvDropdown/index.d.ts +6 -1
  19. package/dist/components/VvDropdownAction/VvDropdownAction.es.js +10 -0
  20. package/dist/components/VvDropdownOptgroup/VvDropdownOptgroup.es.js +237 -0
  21. package/dist/components/VvDropdownOptgroup/VvDropdownOptgroup.umd.js +1 -0
  22. package/dist/components/VvDropdownOption/VvDropdownOption.es.js +10 -0
  23. package/dist/components/VvInputText/VvInputText.es.js +14 -4
  24. package/dist/components/VvInputText/VvInputText.umd.js +1 -1
  25. package/dist/components/VvInputText/VvInputText.vue.d.ts +4 -4
  26. package/dist/components/VvInputText/index.d.ts +2 -2
  27. package/dist/components/VvProgress/VvProgress.es.js +10 -0
  28. package/dist/components/VvRadio/VvRadio.es.js +10 -0
  29. package/dist/components/VvRadioGroup/VvRadioGroup.es.js +17 -1
  30. package/dist/components/VvRadioGroup/VvRadioGroup.umd.js +1 -1
  31. package/dist/components/VvSelect/VvSelect.es.js +52 -10
  32. package/dist/components/VvSelect/VvSelect.umd.js +1 -1
  33. package/dist/components/VvSelect/VvSelect.vue.d.ts +4 -3
  34. package/dist/components/VvTextarea/VvTextarea.es.js +14 -4
  35. package/dist/components/VvTextarea/VvTextarea.umd.js +1 -1
  36. package/dist/components/VvTextarea/VvTextarea.vue.d.ts +10 -10
  37. package/dist/components/VvTextarea/index.d.ts +2 -2
  38. package/dist/components/VvTooltip/VvTooltip.es.js +10 -0
  39. package/dist/components/index.es.js +250 -140
  40. package/dist/components/index.umd.js +1 -1
  41. package/dist/composables/useOptions.d.ts +1 -0
  42. package/dist/directives/index.d.ts +1 -0
  43. package/dist/directives/index.es.js +51 -2
  44. package/dist/directives/index.umd.js +1 -1
  45. package/dist/directives/v-contextmenu.d.ts +3 -0
  46. package/dist/directives/v-contextmenu.es.js +42 -0
  47. package/dist/directives/v-contextmenu.umd.js +1 -0
  48. package/dist/directives/v-tooltip.es.js +10 -0
  49. package/dist/icons.d.ts +3 -1
  50. package/dist/icons.es.js +6 -4
  51. package/dist/icons.umd.js +1 -1
  52. package/dist/props/index.d.ts +11 -3
  53. package/dist/resolvers/unplugin.es.js +2 -1
  54. package/dist/resolvers/unplugin.umd.js +1 -1
  55. package/dist/stories/Combobox/Combobox.settings.d.ts +12 -0
  56. package/dist/stories/Dropdown/Dropdown.settings.d.ts +12 -0
  57. package/dist/stories/argTypes.d.ts +12 -0
  58. package/package.json +58 -42
  59. package/src/assets/icons/detailed.json +1 -1
  60. package/src/assets/icons/normal.json +1 -1
  61. package/src/assets/icons/simple.json +1 -1
  62. package/src/components/VvCombobox/VvCombobox.vue +85 -28
  63. package/src/components/VvDropdown/VvDropdown.vue +3 -2
  64. package/src/components/VvDropdown/VvDropdownOptgroup.vue +18 -0
  65. package/src/components/VvInputText/VvInputText.vue +2 -2
  66. package/src/components/VvSelect/VvSelect.vue +38 -10
  67. package/src/components/VvTextarea/VvTextarea.vue +2 -2
  68. package/src/composables/useOptions.ts +6 -0
  69. package/src/directives/index.ts +2 -0
  70. package/src/directives/v-contextmenu.ts +40 -0
  71. package/src/icons.ts +1 -1
  72. package/src/props/index.ts +12 -2
  73. package/src/resolvers/unplugin.ts +2 -1
  74. package/src/stories/Dropdown/DropdownContextmenuDirective.stories.mdx +41 -0
  75. package/src/stories/Tooltip/TooltipDirective.stories.mdx +1 -1
  76. package/src/stories/argTypes.ts +10 -0
  77. 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'
@@ -155,8 +156,12 @@
155
156
  props.searchable ? filteredOptions.value : props.options,
156
157
  )
157
158
 
158
- const { getOptionLabel, getOptionValue, getOptionDisabled } =
159
- useOptions(props)
159
+ const {
160
+ getOptionLabel,
161
+ getOptionValue,
162
+ getOptionDisabled,
163
+ getOptionGrouped,
164
+ } = useOptions(props)
160
165
 
161
166
  // options filtered by search text
162
167
  const filteredOptions = computed(() => {
@@ -193,7 +198,7 @@
193
198
  const selectedOptions = computed(() => {
194
199
  let selectedValues: Array<typeof props.modelValue> = []
195
200
  if (Array.isArray(props.modelValue)) {
196
- selectedValues = props.modelValue
201
+ selectedValues = props.modelValue as Array<typeof props.modelValue>
197
202
  } else if (props.modelValue) {
198
203
  selectedValues = [props.modelValue]
199
204
  }
@@ -237,10 +242,11 @@
237
242
  if (props.multiple) {
238
243
  // check maxValues prop and block check new values
239
244
  if (Array.isArray(props.modelValue)) {
245
+ const maxValues = Number(props.maxValues)
240
246
  if (
241
247
  props.maxValues !== undefined &&
242
- props.maxValues >= 0 &&
243
- props.modelValue?.length >= props.maxValues
248
+ maxValues >= 0 &&
249
+ props.modelValue?.length >= maxValues
244
250
  ) {
245
251
  if (!contains(value, props.modelValue)) {
246
252
  // maxValues reached
@@ -295,6 +301,7 @@
295
301
  id: hasDropdownId.value,
296
302
  reference: wrapperEl.value,
297
303
  placement: props.placement,
304
+ strategy: props.strategy,
298
305
  transitionName: props.transitionName,
299
306
  offset: props.offset,
300
307
  shift: props.shift,
@@ -325,6 +332,14 @@
325
332
  toggleExpanded()
326
333
  }
327
334
  })
335
+
336
+ // Grouped options
337
+ const isGroup = (option: string | Option) => {
338
+ if (typeof option === 'string') {
339
+ return false
340
+ }
341
+ return option.options && option.options.length > 0
342
+ }
328
343
  </script>
329
344
 
330
345
  <template>
@@ -437,35 +452,77 @@
437
452
  </template>
438
453
  <template #items>
439
454
  <template v-if="filteredOptions.length">
440
- <VvDropdownOption
455
+ <template
441
456
  v-for="(option, index) in filteredOptions"
442
- v-bind="{
443
- disabled: getOptionDisabled(option),
444
- selected: getOptionSelected(option),
445
- unselectable,
446
- deselectHintLabel:
447
- propsDefaults.deselectHintLabel,
448
- selectHintLabel: propsDefaults.selectHintLabel,
449
- selectedHintLabel:
450
- propsDefaults.selectedHintLabel,
451
- }"
452
457
  :key="index"
453
- class="vv-dropdown-option"
454
- @click.passive="onInput(option)"
455
458
  >
456
- <!-- @slot Slot for option customization -->
457
- <slot
458
- name="option"
459
+ <template v-if="isGroup(option)">
460
+ <VvDropdownOptgroup
461
+ :label="getOptionLabel(option)"
462
+ />
463
+ <VvDropdownOption
464
+ v-for="(item, i) in getOptionGrouped(
465
+ option,
466
+ )"
467
+ v-bind="{
468
+ disabled: getOptionDisabled(item),
469
+ selected: getOptionSelected(item),
470
+ unselectable,
471
+ deselectHintLabel:
472
+ propsDefaults.deselectHintLabel,
473
+ selectHintLabel:
474
+ propsDefaults.selectHintLabel,
475
+ selectedHintLabel:
476
+ propsDefaults.selectedHintLabel,
477
+ }"
478
+ :key="i"
479
+ class="vv-dropdown-option"
480
+ @click.passive="onInput(item)"
481
+ >
482
+ <!-- @slot Slot for option customization -->
483
+ <slot
484
+ name="option"
485
+ v-bind="{
486
+ option,
487
+ selectedOptions,
488
+ selected: getOptionSelected(item),
489
+ disabled: getOptionDisabled(item),
490
+ }"
491
+ >
492
+ {{ getOptionLabel(item) }}
493
+ </slot>
494
+ </VvDropdownOption>
495
+ </template>
496
+ <VvDropdownOption
497
+ v-else
459
498
  v-bind="{
460
- option,
461
- selectedOptions,
462
- selected: getOptionSelected(option),
463
499
  disabled: getOptionDisabled(option),
500
+ selected: getOptionSelected(option),
501
+ unselectable,
502
+ deselectHintLabel:
503
+ propsDefaults.deselectHintLabel,
504
+ selectHintLabel:
505
+ propsDefaults.selectHintLabel,
506
+ selectedHintLabel:
507
+ propsDefaults.selectedHintLabel,
464
508
  }"
509
+ class="vv-dropdown-option"
510
+ @click.passive="onInput(option)"
465
511
  >
466
- {{ getOptionLabel(option) }}
467
- </slot>
468
- </VvDropdownOption>
512
+ <!-- @slot Slot for option customization -->
513
+ <slot
514
+ name="option"
515
+ v-bind="{
516
+ option,
517
+ selectedOptions,
518
+ selected: getOptionSelected(option),
519
+ disabled: getOptionDisabled(option),
520
+ }"
521
+ >
522
+ {{ getOptionLabel(option) }}
523
+ </slot>
524
+ </VvDropdownOption>
525
+ </template>
469
526
  </template>
470
527
  <VvDropdownOption
471
528
  v-else-if="!options.length"
@@ -25,7 +25,6 @@
25
25
  ShiftOptions,
26
26
  SizeOptions,
27
27
  } from '../../types/floating-ui'
28
- import type { Placement } from '@/constants'
29
28
 
30
29
  // props, emit and attrs
31
30
  const props = defineProps(VvDropdownProps)
@@ -128,7 +127,8 @@
128
127
  floatingEl,
129
128
  {
130
129
  whileElementsMounted: autoUpdate,
131
- placement: props.placement as Placement,
130
+ placement: computed(() => props.placement),
131
+ strategy: computed(() => props.strategy),
132
132
  middleware,
133
133
  },
134
134
  )
@@ -195,6 +195,7 @@
195
195
  const init = (el: HTMLElement) => {
196
196
  referenceEl.value = el
197
197
  }
198
+ defineExpose({ toggle, show, hide, init })
198
199
  watch(expanded, (newValue) => {
199
200
  if (newValue && props.autofocusFirst) {
200
201
  nextTick(() => {
@@ -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>
@@ -147,8 +147,8 @@
147
147
  // count
148
148
  const { formatted: countFormatted } = useTextCount(localModelValue, {
149
149
  mode: props.count,
150
- upperLimit: props.maxlength,
151
- lowerLimit: props.minlength,
150
+ upperLimit: Number(props.maxlength),
151
+ lowerLimit: Number(props.minlength),
152
152
  })
153
153
 
154
154
  // tabindex
@@ -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"
@@ -61,8 +61,8 @@
61
61
  // count
62
62
  const { formatted: countFormatted } = useTextCount(localModelValue, {
63
63
  mode: props.count,
64
- upperLimit: props.maxlength,
65
- lowerLimit: props.minlength,
64
+ upperLimit: Number(props.maxlength),
65
+ lowerLimit: Number(props.minlength),
66
66
  })
67
67
 
68
68
  // tabindex
@@ -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
  }
@@ -1,5 +1,7 @@
1
1
  import tooltip from '../directives/v-tooltip'
2
+ import contextmenu from '../directives/v-contextmenu'
2
3
 
3
4
  export default {
4
5
  tooltip,
6
+ contextmenu,
5
7
  }
@@ -0,0 +1,40 @@
1
+ import type { Directive, DirectiveBinding } from 'vue'
2
+
3
+ const contextmenu: Directive = {
4
+ beforeUpdate(el: HTMLElement, binding: DirectiveBinding) {
5
+ const clientX = ref(0)
6
+ const clientY = ref(0)
7
+ const virtualEl = {
8
+ getBoundingClientRect() {
9
+ return {
10
+ width: 0,
11
+ height: 0,
12
+ x: clientX.value,
13
+ y: clientY.value,
14
+ top: clientY.value,
15
+ left: clientX.value,
16
+ right: clientX.value,
17
+ bottom: clientY.value,
18
+ }
19
+ },
20
+ }
21
+ if (binding.value?.init) {
22
+ binding.value.init?.(virtualEl)
23
+ }
24
+ el.addEventListener(
25
+ 'contextmenu',
26
+ function (ev) {
27
+ if (binding.value?.show) {
28
+ ev.preventDefault()
29
+ clientX.value = ev.clientX
30
+ clientY.value = ev.clientY
31
+ binding.value.show?.()
32
+ return false
33
+ }
34
+ },
35
+ false,
36
+ )
37
+ },
38
+ }
39
+
40
+ export default contextmenu
package/src/icons.ts CHANGED
@@ -4,4 +4,4 @@ import simple from './assets/icons/simple.json'
4
4
 
5
5
  export default [normal, detailed, simple]
6
6
 
7
- export { normal }
7
+ export { normal, detailed, simple }
@@ -235,6 +235,16 @@ export const DropdownProps = {
235
235
  )
236
236
  },
237
237
  },
238
+ /**
239
+ * Dropdown strategy
240
+ */
241
+ strategy: {
242
+ type: String as PropType<'fixed' | 'absolute'>,
243
+ default: 'absolute',
244
+ validator: (value: 'fixed' | 'absolute') => {
245
+ return ['fixed', 'absolute'].includes(value)
246
+ },
247
+ },
238
248
  /**
239
249
  * Dropdown show / hide transition name
240
250
  */
@@ -362,14 +372,14 @@ export const InputTextareaProps = {
362
372
  * Available for input types: text, search, url, tel, email, password
363
373
  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#minlength
364
374
  */
365
- minlength: Number,
375
+ minlength: [String, Number],
366
376
  /**
367
377
  * Input / Textarea maxlength
368
378
  * Maximum length (number of characters) of value
369
379
  * Available for input types: text, search, url, tel, email, password
370
380
  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#maxlength
371
381
  */
372
- maxlength: Number,
382
+ maxlength: [String, Number],
373
383
  /**
374
384
  * Input / Textarea placeholder
375
385
  * Text that appears in the form control when it has no value set
@@ -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
  }
@@ -0,0 +1,41 @@
1
+ import { ref } from 'vue'
2
+ import { Meta, Story, Canvas } from '@storybook/addon-docs'
3
+ import { defaultArgs, argTypes } from './Dropdown.settings'
4
+ import VvDropdown from '@/components/VvDropdown/VvDropdown.vue'
5
+ import VvDropdownAction from '@/components/VvDropdown/VvDropdownAction.vue'
6
+ import VvIcon from '@/components/VvIcon/VvIcon.vue'
7
+
8
+ <Meta title="Directives/Contextmenu" args={defaultArgs} argTypes={argTypes} />
9
+
10
+ export const Template = (args, { argTypes }) => ({
11
+ props: Object.keys(argTypes),
12
+ components: { VvDropdown, VvDropdownAction, VvIcon },
13
+ setup() {
14
+ const dropdownEl = ref(null)
15
+ return { args, dropdownEl }
16
+ },
17
+ template: /* html */ `
18
+ <div v-contextmenu="dropdownEl" class="w-full h-320 bg-surface-1 flex items-center justify-center">
19
+ <div class="text-word-2 text-18 uppercase w-150 text-center">Right click context menu</div>
20
+ </div>
21
+ <vv-dropdown v-bind="args" ref="dropdownEl">
22
+ <template #items>
23
+ <vv-dropdown-action>
24
+ <vv-icon name="add" /> Create
25
+ </vv-dropdown-action>
26
+ <vv-dropdown-action>
27
+ <vv-icon name="edit" /> Update
28
+ </vv-dropdown-action>
29
+ <vv-dropdown-action>
30
+ <vv-icon name="trash" /> Delete
31
+ </vv-dropdown-action>
32
+ </template>
33
+ </vv-dropdown>
34
+ `,
35
+ })
36
+
37
+ <Canvas>
38
+ <Story name="Default" args={{ placement: 'bottom-start' }}>
39
+ {Template.bind()}
40
+ </Story>
41
+ </Canvas>
@@ -5,7 +5,7 @@ import { defaultArgs, argTypes } from './Tooltip.settings'
5
5
  import { defaultTest } from './Tooltip.test'
6
6
 
7
7
  <Meta
8
- title="Components/Tooltip/Directive"
8
+ title="Directives/Tooltip"
9
9
  component={VvTooltip}
10
10
  args={defaultArgs}
11
11
  argTypes={argTypes}
@@ -298,6 +298,16 @@ export const DropdownArgTypes = {
298
298
  defaultValue: { summary: 'bottom' },
299
299
  },
300
300
  },
301
+ strategy: {
302
+ description: 'Dropdown strategy',
303
+ options: ['fixed', 'absolute'],
304
+ control: {
305
+ type: 'select',
306
+ },
307
+ table: {
308
+ defaultValue: { summary: 'absolute' },
309
+ },
310
+ },
301
311
  transitionName: {
302
312
  description: 'Dropdown show / hide transition name',
303
313
  control: {
@@ -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
  }