mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-09-04 17:23:25 +00:00
feat(messages): overhaul messaging and contact flows
This commit is contained in:
@@ -23,6 +23,9 @@ describe('SkyDropdown', () => {
|
||||
it('supports checked, submenu, destructive, disabled, and divided items', () => {
|
||||
expect(component).toContain("'menuitemradio'")
|
||||
expect(component).toContain(':aria-checked=')
|
||||
expect(component).toContain("section.group ? 'group' : 'presentation'")
|
||||
expect(component).toContain('section.group ? section.label : undefined')
|
||||
expect(component).toContain('groupLabel?: string')
|
||||
expect(component).toContain(':aria-haspopup=')
|
||||
expect(component).toContain('item.destructive')
|
||||
expect(component).toContain('item.disabled')
|
||||
@@ -35,9 +38,7 @@ describe('SkyDropdown', () => {
|
||||
expect(overlays).toMatch(
|
||||
/\.sky-dropdown__item\s*\{[^}]*min-height:\s*var\(--sky-touch-target, 44px\)/s,
|
||||
)
|
||||
expect(overlays).toMatch(
|
||||
/\.sky-dropdown__menu\s*\{[^}]*padding:\s*6px;/s,
|
||||
)
|
||||
expect(overlays).toMatch(/\.sky-dropdown__menu\s*\{[^}]*padding:\s*6px;/s)
|
||||
expect(overlays).toMatch(
|
||||
/\.sky-dropdown__item\s*\{[^}]*border-radius:\s*12px;/s,
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { Check, ChevronRight } from 'lucide-vue-next'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import SkyPopover from './SkyPopover.vue'
|
||||
|
||||
@@ -9,13 +10,15 @@ interface SkyDropdownItem {
|
||||
checked?: boolean
|
||||
destructive?: boolean
|
||||
disabled?: boolean
|
||||
group?: string
|
||||
groupLabel?: string
|
||||
id: string
|
||||
label: string
|
||||
separatorBefore?: boolean
|
||||
submenu?: boolean
|
||||
}
|
||||
|
||||
withDefaults(
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
items: readonly SkyDropdownItem[]
|
||||
label: string
|
||||
@@ -34,6 +37,33 @@ const emit = defineEmits<{
|
||||
positionerror: [reason: string]
|
||||
select: [id: string, event: MouseEvent]
|
||||
}>()
|
||||
|
||||
const menuSections = computed(() => {
|
||||
const sections: Array<{
|
||||
group: string | null
|
||||
items: SkyDropdownItem[]
|
||||
key: string
|
||||
label?: string
|
||||
}> = []
|
||||
|
||||
props.items.forEach((item) => {
|
||||
const group = item.group ?? null
|
||||
const previous = sections[sections.length - 1]
|
||||
if (!previous || previous.group !== group) {
|
||||
sections.push({
|
||||
group,
|
||||
items: [item],
|
||||
key: `${group ?? 'items'}:${sections.length}`,
|
||||
label: item.groupLabel,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
previous.items.push(item)
|
||||
})
|
||||
|
||||
return sections
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -50,33 +80,40 @@ const emit = defineEmits<{
|
||||
@positionerror="emit('positionerror', $event)"
|
||||
>
|
||||
<div class="sky-dropdown__menu">
|
||||
<button
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
class="sky-dropdown__item"
|
||||
:class="{
|
||||
'sky-dropdown__item--destructive': item.destructive,
|
||||
'sky-dropdown__item--separator': item.separatorBefore,
|
||||
}"
|
||||
:aria-checked="item.checked === undefined ? undefined : item.checked"
|
||||
:aria-haspopup="item.submenu ? 'menu' : undefined"
|
||||
:disabled="item.disabled"
|
||||
:role="item.checked === undefined ? 'menuitem' : 'menuitemradio'"
|
||||
type="button"
|
||||
@click="emit('select', item.id, $event)"
|
||||
<div
|
||||
v-for="section in menuSections"
|
||||
:key="section.key"
|
||||
:aria-label="section.group ? section.label : undefined"
|
||||
:role="section.group ? 'group' : 'presentation'"
|
||||
>
|
||||
<span class="sky-dropdown__indicator" aria-hidden="true">
|
||||
<Check v-if="item.checked" :size="21" :stroke-width="2.5" />
|
||||
</span>
|
||||
<span class="sky-dropdown__label">{{ item.label }}</span>
|
||||
<ChevronRight
|
||||
v-if="item.submenu"
|
||||
class="sky-dropdown__chevron"
|
||||
:size="21"
|
||||
:stroke-width="2.5"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
v-for="item in section.items"
|
||||
:key="item.id"
|
||||
class="sky-dropdown__item"
|
||||
:class="{
|
||||
'sky-dropdown__item--destructive': item.destructive,
|
||||
'sky-dropdown__item--separator': item.separatorBefore,
|
||||
}"
|
||||
:aria-checked="item.checked === undefined ? undefined : item.checked"
|
||||
:aria-haspopup="item.submenu ? 'menu' : undefined"
|
||||
:disabled="item.disabled"
|
||||
:role="item.checked === undefined ? 'menuitem' : 'menuitemradio'"
|
||||
type="button"
|
||||
@click="emit('select', item.id, $event)"
|
||||
>
|
||||
<span class="sky-dropdown__indicator" aria-hidden="true">
|
||||
<Check v-if="item.checked" :size="21" :stroke-width="2.5" />
|
||||
</span>
|
||||
<span class="sky-dropdown__label">{{ item.label }}</span>
|
||||
<ChevronRight
|
||||
v-if="item.submenu"
|
||||
class="sky-dropdown__chevron"
|
||||
:size="21"
|
||||
:stroke-width="2.5"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</SkyPopover>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user