mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
feat(kit): render the chips with UiChip and UiButton
UiChip is a non-interactive label chip and renders the voice card's chips. The pressable chips and pills are pressed toggles, so the rail card chips, map source chips and city and place pills render through UiButton with pressedClass, keeping their classes, attributes and the classes other code adds. The pills now report aria-pressed.
This commit is contained in:
1 parent
d98a7c81be
commit
28ca784d49
10 files changed
+81
-16
No files matched your search
@@ -0,0 +1,28 @@
|
||||
import { after, before, test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { installVueDom } from '../../testSupport/vueDom.mjs';
|
||||
|
||||
let mount;
|
||||
let UiChip;
|
||||
let uninstall;
|
||||
before(async () => {
|
||||
uninstall = installVueDom();
|
||||
({ mount } = await import('@vue/test-utils'));
|
||||
UiChip = (await import('./UiChip.vue')).default;
|
||||
});
|
||||
after(() => uninstall());
|
||||
|
||||
test('a chip is a span with the kit classes and Core’s', async () => {
|
||||
const wrapper = mount(UiChip, {
|
||||
attrs: { class: 'gev-voice-card-chip', 'data-tone': 'ok' },
|
||||
slots: { default: 'ok' },
|
||||
});
|
||||
const chip = wrapper.get('span');
|
||||
assert.deepEqual(chip.classes(), ['ui-chip', 'gev-voice-card-chip']);
|
||||
assert.equal(chip.attributes('data-tone'), 'ok');
|
||||
assert.equal(chip.text(), 'ok');
|
||||
await wrapper.setProps({ selected: true, mono: true });
|
||||
assert.ok(chip.classes().includes('ui-chip--selected'));
|
||||
assert.ok(chip.classes().includes('ui-mono'));
|
||||
wrapper.unmount();
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
<script setup>
|
||||
// Core's chip, with @halfpixel/ui-vue UiChip's props and classes so the two
|
||||
// kits can merge: a label that says what something is, never a control.
|
||||
// Core styles it through the classes its callers pass; the kit classes carry
|
||||
// no Core styles yet. A chip that presses is a UiButton with pressedClass.
|
||||
defineProps({
|
||||
selected: { type: Boolean, default: false },
|
||||
mono: { type: Boolean, default: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span
|
||||
class="ui-chip"
|
||||
:class="{ 'ui-chip--selected': selected, 'ui-mono': mono }"
|
||||
>
|
||||
<slot />
|
||||
</span>
|
||||
</template>
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup>
|
||||
import UiButton from '../kit/UiButton.vue';
|
||||
|
||||
// Keyed chips shared by rail cards; the owner decides what a click does.
|
||||
defineProps({
|
||||
chips: { type: Array, default: () => [] },
|
||||
@@ -6,23 +8,23 @@ defineProps({
|
||||
});
|
||||
|
||||
const chipClass = (chip) =>
|
||||
`data-toggle-chip chip-${chip.state || (chip.active ? 'active' : 'idle')}${chip.active ? ' active' : ''}`;
|
||||
`data-toggle-chip chip-${chip.state || (chip.active ? 'active' : 'idle')}`;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
<UiButton
|
||||
v-for="chip in chips"
|
||||
:key="chip.id"
|
||||
type="button"
|
||||
:data-chip-id="chip.id"
|
||||
:class="chipClass(chip)"
|
||||
:pressed="Boolean(chip.active)"
|
||||
pressed-class="active"
|
||||
:style="chip.color ? `--chip-color: ${chip.color}` : undefined"
|
||||
:data-chip-color="chip.color || undefined"
|
||||
:title="chip.title || undefined"
|
||||
:disabled="Boolean(chip.disabled)"
|
||||
:aria-pressed="String(Boolean(chip.active))"
|
||||
:aria-busy="String(Boolean(chip.busy))"
|
||||
@click="onSelect(chip)"
|
||||
>{{ chip.label }}</button
|
||||
>{{ chip.label }}</UiButton
|
||||
>
|
||||
</template>
|
||||
@@ -117,7 +117,7 @@ function selectMapSource(chip) {
|
||||
<span data-i18n id="map-source-label">MAP SOURCE</span>
|
||||
<span id="map-stack-status" class="pp-stack-status" v-class-toggle="{ warn: !!mapSource?.status.warn }" aria-live="polite">{{ mapSource ? mapSource.status.text : '3D' }}</span>
|
||||
</div>
|
||||
<div id="map-stack-chips" class="map-stack-chip-row" role="group" aria-label="Map source" data-i18n-aria-label><button v-for="chip in mapSource?.chips" :key="chip.id" type="button" class="map-stack-chip" v-class-toggle="{ active: chip.active, unavailable: !chip.available }" :data-stack-id="chip.id" :title="chip.title" :aria-pressed="String(chip.active)" :aria-disabled="String(!chip.available)" :aria-label="chip.ariaLabel" @click="selectMapSource(chip)"><span class="map-stack-chip-label">{{ chip.label }}</span><span v-if="chip.requirement" class="map-stack-chip-req">{{ chip.requirement }}</span></button></div>
|
||||
<div id="map-stack-chips" class="map-stack-chip-row" role="group" aria-label="Map source" data-i18n-aria-label><UiButton v-for="chip in mapSource?.chips" :key="chip.id" class="map-stack-chip" :pressed="Boolean(chip.active)" pressed-class="active" v-class-toggle="{ unavailable: !chip.available }" :data-stack-id="chip.id" :title="chip.title" :aria-disabled="String(!chip.available)" :aria-label="chip.ariaLabel" @click="selectMapSource(chip)"><span class="map-stack-chip-label">{{ chip.label }}</span><span v-if="chip.requirement" class="map-stack-chip-req">{{ chip.requirement }}</span></UiButton></div>
|
||||
</section>
|
||||
</div>
|
||||
<div id="style-mini-status" class="panel-mini-status" aria-live="polite">
|
||||
@@ -145,10 +145,10 @@ function selectMapSource(chip) {
|
||||
</div>
|
||||
<div id="location-bar-popover" class="dock-popover-content">
|
||||
<UiButton variant="icon" class="dock-pin-btn" data-pin-target="location-bar" :label="t('Pin location tray')" :title="t('Keep location tray open')" :pressed="!!panels['location-bar']?.pinned" @click="pin($event, 'location-bar')"><img src="/pin.svg" alt="" /></UiButton>
|
||||
<div id="poi-row" class="poi-row-container" v-class-toggle="{ expanded: !!loc?.poisExpanded }"><button v-for="poi in loc?.pois" :key="`${loc.poiCity}:${poi.index}`" type="button" class="poi-pill" v-class-toggle="{ active: poi.active }" :data-poi-index="poi.index" @click="locationControls?.choosePoi(poi.index)"><span class="poi-pill-key">{{ poi.key }}</span><span class="poi-pill-name">{{ poi.name }}</span></button></div>
|
||||
<div id="poi-row" class="poi-row-container" v-class-toggle="{ expanded: !!loc?.poisExpanded }"><UiButton v-for="poi in loc?.pois" :key="`${loc.poiCity}:${poi.index}`" class="poi-pill" :pressed="Boolean(poi.active)" pressed-class="active" :data-poi-index="poi.index" @click="locationControls?.choosePoi(poi.index)"><span class="poi-pill-key">{{ poi.key }}</span><span class="poi-pill-name">{{ poi.name }}</span></UiButton></div>
|
||||
<div class="location-bar-divider" id="location-bar-divider" v-class-toggle="{ visible: !!loc?.poisExpanded }"></div>
|
||||
<div class="location-city-row">
|
||||
<div id="location-pills" class="location-pills"><button v-for="city in loc?.cities" :key="city.id" type="button" class="location-pill" v-class-toggle="{ active: city.active }" :data-location-id="city.id" @click="locationControls?.chooseCity(city.id)">{{ city.label }}</button></div>
|
||||
<div id="location-pills" class="location-pills"><UiButton v-for="city in loc?.cities" :key="city.id" class="location-pill" :pressed="Boolean(city.active)" pressed-class="active" :data-location-id="city.id" @click="locationControls?.chooseCity(city.id)">{{ city.label }}</UiButton></div>
|
||||
<div class="location-search-wrap">
|
||||
<button id="search-toggle" class="search-toggle-btn" title="Search any location" data-i18n-title>
|
||||
<span>🔎</span>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup>
|
||||
import { t } from '../../../i18n/index.js';
|
||||
import { ASSISTANT_NAME } from '../../../voice/control.js';
|
||||
import UiChip from '../../kit/UiChip.vue';
|
||||
|
||||
// Captions, plan and result, as VoiceCardControls (src/voice/voiceCard.js)
|
||||
// presents them. Captions update silently; the polite live region carries
|
||||
@@ -22,7 +23,7 @@ const emit = defineEmits(['dismiss']);
|
||||
<ol id="gev-voice-card-plan" class="gev-voice-card-plan" :aria-label="t('Plan')" :hidden="card.steps.length === 0"><li v-for="(step, index) in card.steps" :key="step.key ?? index" class="gev-voice-card-step" :data-status="step.status"><span class="gev-voice-card-step-label">{{ step.label }}</span><span class="gev-voice-card-sr">{{ step.statusText ? `, ${step.statusText}` : '' }}</span><span v-if="step.detail" class="gev-voice-card-step-detail">{{ step.detail }}</span></li></ol>
|
||||
<div id="gev-voice-card-result" class="gev-voice-card-result" :hidden="!card.result.visible">
|
||||
<div id="gev-voice-card-result-title" class="gev-voice-card-result-title">{{ card.result.title }}</div>
|
||||
<div id="gev-voice-card-chips" class="gev-voice-card-chips" :hidden="card.result.chips.length === 0"><span v-for="(chip, index) in card.result.chips" :key="index" class="gev-voice-card-chip" :data-tone="chip">{{ chip }}</span></div>
|
||||
<div id="gev-voice-card-chips" class="gev-voice-card-chips" :hidden="card.result.chips.length === 0"><UiChip v-for="(chip, index) in card.result.chips" :key="index" class="gev-voice-card-chip" :data-tone="chip">{{ chip }}</UiChip></div>
|
||||
<ul id="gev-voice-card-lines" class="gev-voice-card-lines"><li v-for="(line, index) in card.result.lines" :key="index">{{ line }}</li></ul>
|
||||
<ol id="gev-voice-card-referents" class="gev-voice-card-referents" :aria-label="t('Referenced items')" :hidden="card.result.referents.length === 0"><li v-for="(ref, index) in card.result.referents" :key="index" :value="ref.n">{{ ref.label }}</li></ol>
|
||||
<details id="gev-voice-card-notes" class="gev-voice-card-notes" :hidden="card.result.notes.length === 0">
|
||||
|
||||
Reference in new issue
Block a user