Skip to content

Commit 5649568

Browse files
committed
fixup! feat: add NcFormBoxSelectNative
1 parent 772cac3 commit 5649568

File tree

2 files changed

+30
-21
lines changed

2 files changed

+30
-21
lines changed

src/components/NcFormBox/NcFormBoxItem.vue

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ const {
3333
class?: VueClassType
3434
/** Interactive item classes */
3535
itemClasses?: VueClassType
36+
/** Disable clickable overlay from the interactive item element to manually implement */
37+
pure?: boolean
3638
}>()
3739
3840
defineEmits<{
@@ -52,7 +54,15 @@ const slots = defineSlots<{
5254
descriptionId?: string
5355
}>
5456
/** Icon content */
55-
icon?: Slot
57+
icon?: Slot<{
58+
/** IDRef of the description element if present */
59+
descriptionId?: string
60+
}>
61+
/** Extra content slot for additional overlays */
62+
extra?: Slot<{
63+
/** IDRef of the description element if present */
64+
descriptionId?: string
65+
}>
5666
}>()
5767
5868
const { formBoxItemClass } = useNcFormBox()
@@ -75,15 +85,15 @@ const hasDescription = () => !!description || !!slots.description
7585
<span :class="$style.formBoxItem__content">
7686
<component
7787
:is="tag"
78-
:class="[$style.formBoxItem__element, itemClasses]"
88+
:class="[$style.formBoxItem__element, itemClasses, { [$style.formBoxItem__element_clickable]: !pure }]"
7989
v-bind="$attrs"
8090
@click="$emit('click', $event)">
8191
<slot :description-id>
8292
{{ label || '⚠️ Label is missing' }}
8393
</slot>
8494
</component>
8595
<span v-if="hasDescription()" :id="descriptionId" :class="$style.formBoxItem__description">
86-
<slot name="description">
96+
<slot name="description" :description-id>
8797
{{ description }}
8898
</slot>
8999
</span>
@@ -93,6 +103,7 @@ const hasDescription = () => !!description || !!slots.description
93103
⚠️ Icon is missing
94104
</slot>
95105
</span>
106+
<slot name="extra" :description-id />
96107
</div>
97108
</template>
98109

@@ -169,7 +180,7 @@ const hasDescription = () => !!description || !!slots.description
169180
170181
// A trick for accessibility:
171182
// make entire component clickable while internally splitting the interactive item and the description
172-
.formBoxItem__element::after {
183+
.formBoxItem__element_clickable::after {
173184
content: '';
174185
position: absolute;
175186
inset: 0;

src/components/NcFormBoxSelectNative/NcFormBoxSelectNative.vue

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
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 } from 'vue'
99
import NcFormBoxItem from '../NcFormBox/NcFormBoxItem.vue'
10+
import NcIconSvgWrapper from '../NcIconSvgWrapper/NcIconSvgWrapper.vue'
11+
import { createElementId } from '../../utils/createElementId.ts'
1012
1113
/** Selected value */
1214
const modelValue = defineModel<T>({ required: true })
@@ -27,8 +29,7 @@ const {
2729
disabled?: boolean
2830
}>()
2931
30-
const selectId = useId()
31-
const selectElement = useTemplateRef('select')
32+
const selectId = createElementId()
3233
const selectedLabel = computed(() => options.find((option) => option.value === modelValue.value)?.label)
3334
</script>
3435

@@ -39,15 +40,16 @@ const selectedLabel = computed(() => options.find((option) => option.value === m
3940
:label
4041
:description="selectedLabel"
4142
:disabled
42-
inverted-accent
43-
@click.prevent="selectElement!.showPicker() /* Not available in old Safari */">
44-
<template #icon="{ descriptionId }">
45-
<IconUnfoldMoreHorizontal :size="20" />
43+
pure
44+
inverted-accent>
45+
<template #icon>
46+
<NcIconSvgWrapper :path="mdiUnfoldMoreHorizontal" inline />
47+
</template>
48+
<template #extra="{ descriptionId }">
4649
<select
4750
:id="selectId"
48-
ref="select"
4951
v-model="modelValue"
50-
class="hidden-select"
52+
:class="$style.hiddenSelect"
5153
:aria-describedby="descriptionId">
5254
<option v-for="option in options" :key="option.value" :value="option.value">
5355
{{ option.label }}
@@ -58,19 +60,15 @@ const selectedLabel = computed(() => options.find((option) => option.value === m
5860
</template>
5961

6062
<!-- TODO: module -->
61-
<style scoped>
62-
.hidden-select {
63+
<style lang="scss" module>
64+
.hiddenSelect {
6365
position: absolute;
6466
inset: 0;
6567
margin: 0;
6668
height: auto;
69+
cursor: pointer;
6770
/* TODO: does it work well cross-browser? */
6871
opacity: 0;
69-
pointer-events: none;
70-
71-
option {
72-
pointer-events: all;
73-
}
7472
}
7573
</style>
7674

0 commit comments

Comments
 (0)