44 -->
55
66<script setup lang="ts" generic =" T extends string " >
7- import { computed , useId , useTemplateRef } from ' vue '
8- import IconUnfoldMoreHorizontal from ' vue-material-design-icons/UnfoldMoreHorizontal. vue'
7+ import { mdiUnfoldMoreHorizontal } from ' @mdi/js '
8+ import { computed , useTemplateRef } from ' vue'
99import NcFormBoxItem from ' ../NcFormBox/NcFormBoxItem.vue'
10+ import NcIconSvgWrapper from ' ../NcIconSvgWrapper/NcIconSvgWrapper.vue'
11+ import { createElementId } from ' ../../utils/createElementId.ts'
1012
1113/** Selected value */
1214const modelValue = defineModel <T >({ required: true })
@@ -27,9 +29,29 @@ const {
2729 disabled? : boolean
2830}>()
2931
30- const selectId = useId ()
32+ const selectId = createElementId ()
3133const selectElement = useTemplateRef (' select' )
34+
3235const selectedLabel = computed (() => options .find ((option ) => option .value === modelValue .value )?.label )
36+
37+ // .showPicker() is not available some browsers (e.g. Safari)
38+ // When the method is not available, we keep select overlay clickable not invisible
39+ // When the method is available, hidden select is not directly clickable but opens programmatically
40+ // The last approach looks slightly better without focusing select by click
41+ const isShowPickerAvailable = ' showPicker' in HTMLSelectElement .prototype
42+
43+ /**
44+ * Handle label click to open the native select picker if possible.
45+ *
46+ * @param event - Click event
47+ */
48+ function onLabelClick(event : MouseEvent ) {
49+ if (! isShowPickerAvailable ) {
50+ return
51+ }
52+ event ?.preventDefault ()
53+ selectElement .value ! .showPicker ()
54+ }
3355 </script >
3456
3557<template >
@@ -39,15 +61,18 @@ const selectedLabel = computed(() => options.find((option) => option.value === m
3961 :label
4062 :description =" selectedLabel"
4163 :disabled
64+ :pure =" !isShowPickerAvailable"
4265 inverted-accent
43- @click.prevent =" selectElement!.showPicker() /* Not available in old Safari */" >
44- <template #icon =" { descriptionId } " >
45- <IconUnfoldMoreHorizontal :size =" 20" />
66+ @click =" onLabelClick" >
67+ <template #icon >
68+ <NcIconSvgWrapper :path =" mdiUnfoldMoreHorizontal" inline />
69+ </template >
70+ <template #extra =" { descriptionId } " >
4671 <select
4772 :id =" selectId"
4873 ref =" select"
4974 v-model =" modelValue"
50- class =" hidden-select "
75+ : class =" [$style.hiddenSelect, { [$style.hiddenSelect_manual]: isShowPickerAvailable }] "
5176 :aria-describedby =" descriptionId" >
5277 <option v-for =" option in options" :key =" option.value" :value =" option.value" >
5378 {{ option.label }}
@@ -57,20 +82,20 @@ const selectedLabel = computed(() => options.find((option) => option.value === m
5782 </NcFormBoxItem >
5883</template >
5984
60- <!-- TODO: module -->
61- <style scoped>
62- .hidden-select {
85+ <style lang="scss" module>
86+ .hiddenSelect {
6387 position : absolute ;
6488 inset : 0 ;
6589 margin : 0 ;
6690 height : auto ;
91+ cursor : pointer ;
6792 /* TODO: does it work well cross-browser? */
6893 opacity : 0 ;
69- pointer-events : none ;
94+ }
7095
71- option {
72- pointer-events : all ;
73- }
96+ // Select is open manual instead of opening by click on invisible select
97+ .hiddenSelect_manual {
98+ pointer-events : none ;
7499}
75100 </style >
76101
0 commit comments