@tekkare/romulus 0.1.65 → 0.1.66
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.
package/dist/module.json
CHANGED
|
@@ -1,103 +1,83 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
RmLangSelect -
|
|
2
|
+
RmLangSelect - bascule de langue, un drapeau par langue dans une capsule.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
Meme dessin que la bascule du rail (`.rm-lang` de shell.css) : les langues
|
|
5
|
+
sont toutes posees, celle qui vaut est en couleur, les autres en gris, et un
|
|
6
|
+
pouce blanc glisse sous la langue active. Rien ne se deroule : a deux ou trois
|
|
7
|
+
langues, un menu demande deux gestes la ou la bascule en demande un, et cache
|
|
8
|
+
la moitie du choix entre les deux.
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
Les drapeaux passent par `RmFlag`, pas par l'emoji : sous Windows, Segoe UI
|
|
11
|
+
Emoji ne ligature pas les indicateurs regionaux et Chrome affiche « FR » dans
|
|
12
|
+
deux carres.
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
`collapsed` remplace le `sidebarOpen` a trois etats (`true`, `false`, `null`)
|
|
15
|
-
d'Auriga, qui melangeait « barre repliee » et « pas dans une barre » dans la
|
|
16
|
-
meme valeur.
|
|
14
|
+
Le gris n'est pas le seul signal : la langue active porte `aria-pressed` et
|
|
15
|
+
son pouce, si bien qu'elle se repere sans distinguer les couleurs.
|
|
17
16
|
-->
|
|
18
17
|
<script setup lang="ts">
|
|
19
|
-
import { computed
|
|
18
|
+
import { computed } from 'vue'
|
|
20
19
|
|
|
21
20
|
export interface RmLang {
|
|
22
|
-
/** Code
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
|
|
21
|
+
/** Code de langue, ce que porte le modele (`fr`, `en`). */
|
|
22
|
+
code: string
|
|
23
|
+
/** Code ISO 3166-1 alpha-2 du drapeau (`fr`, `gb`). Sans lui, `code` sert. */
|
|
24
|
+
iso?: string
|
|
25
|
+
/** Nom de la langue, lu a voix haute et pose en infobulle. */
|
|
26
|
+
label: string
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
const props = withDefaults(defineProps<{
|
|
29
30
|
langs: RmLang[]
|
|
30
|
-
/**
|
|
31
|
-
|
|
32
|
-
/** Intitule du
|
|
31
|
+
/** Cote a cote plutot qu'empile, pour un pied de page ou une barre. */
|
|
32
|
+
horizontal?: boolean
|
|
33
|
+
/** Intitule du groupe pour les technologies d'assistance. */
|
|
33
34
|
label?: string
|
|
34
35
|
}>(), {
|
|
35
|
-
|
|
36
|
+
horizontal: false,
|
|
36
37
|
label: 'Langue',
|
|
37
38
|
})
|
|
38
39
|
|
|
39
40
|
const selected = defineModel<string>({ default: '' })
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const others = computed(() => props.langs.filter(lang => lang.iso !== selected.value))
|
|
46
|
-
|
|
47
|
-
function pick(lang: RmLang) {
|
|
48
|
-
selected.value = lang.iso
|
|
49
|
-
isOpen.value = false
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function onClickOutside(event: Event) {
|
|
53
|
-
if (wrapperRef.value && !wrapperRef.value.contains(event.target as Node)) isOpen.value = false
|
|
54
|
-
}
|
|
42
|
+
/** Rang de la langue active : c'est lui qui place le pouce. */
|
|
43
|
+
const activeIndex = computed(() =>
|
|
44
|
+
Math.max(0, props.langs.findIndex(lang => lang.code === selected.value)),
|
|
45
|
+
)
|
|
55
46
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
47
|
+
/** 32px de pastille plus 2px de gouttiere. */
|
|
48
|
+
const STEP = 34
|
|
59
49
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
document.removeEventListener('click', onClickOutside)
|
|
66
|
-
document.removeEventListener('keydown', onKeydown)
|
|
67
|
-
})
|
|
50
|
+
const thumbStyle = computed(() => ({
|
|
51
|
+
transform: props.horizontal
|
|
52
|
+
? `translateX(${activeIndex.value * STEP}px)`
|
|
53
|
+
: `translateY(${activeIndex.value * STEP}px)`,
|
|
54
|
+
}))
|
|
68
55
|
</script>
|
|
69
56
|
|
|
70
57
|
<template>
|
|
71
|
-
<div
|
|
58
|
+
<div
|
|
59
|
+
class="rm-lang"
|
|
60
|
+
:class="{ 'rm-lang--horizontal': horizontal }"
|
|
61
|
+
role="group"
|
|
62
|
+
:aria-label="label"
|
|
63
|
+
>
|
|
64
|
+
<span class="rm-lang__thumb" :style="thumbStyle" aria-hidden="true" />
|
|
72
65
|
<button
|
|
66
|
+
v-for="lang in langs"
|
|
67
|
+
:key="lang.code"
|
|
73
68
|
type="button"
|
|
74
|
-
class="rm-
|
|
75
|
-
:
|
|
76
|
-
:
|
|
77
|
-
|
|
69
|
+
class="rm-lang__option"
|
|
70
|
+
:class="{ 'rm-lang__option--active': lang.code === selected }"
|
|
71
|
+
:title="lang.label"
|
|
72
|
+
:aria-label="lang.label"
|
|
73
|
+
:aria-pressed="lang.code === selected"
|
|
74
|
+
@click="selected = lang.code"
|
|
78
75
|
>
|
|
79
|
-
<RmFlag :code="
|
|
80
|
-
<span v-if="!collapsed" class="rm-lang__name">{{ current.title }}</span>
|
|
81
|
-
<RmIcon
|
|
82
|
-
v-if="!collapsed"
|
|
83
|
-
name="CaretDown"
|
|
84
|
-
:size="14"
|
|
85
|
-
class="rm-lang__caret"
|
|
86
|
-
:class="{ 'is-open': isOpen }"
|
|
87
|
-
/>
|
|
76
|
+
<RmFlag :code="lang.iso || lang.code" :height="18" />
|
|
88
77
|
</button>
|
|
89
|
-
|
|
90
|
-
<ul v-if="isOpen && others.length > 0" class="rm-lang__list" role="listbox" :aria-label="label">
|
|
91
|
-
<li v-for="lang in others" :key="lang.iso" role="option" :aria-selected="false">
|
|
92
|
-
<button type="button" class="rm-lang__option" @click="pick(lang)">
|
|
93
|
-
<RmFlag :code="lang.iso" :height="18" :title="lang.title" />
|
|
94
|
-
<span v-if="!collapsed">{{ lang.title }}</span>
|
|
95
|
-
</button>
|
|
96
|
-
</li>
|
|
97
|
-
</ul>
|
|
98
78
|
</div>
|
|
99
79
|
</template>
|
|
100
80
|
|
|
101
81
|
<style scoped>
|
|
102
|
-
.rm-lang{
|
|
82
|
+
.rm-lang{background:var(--rm-shell-subtle,var(--bg-surface-2));border:1px solid var(--rm-shell-accent,var(--color-primary));border-radius:9999px;display:grid;gap:2px;grid-template-rows:repeat(v-bind("langs.length"),1fr);padding:3px;position:relative;width:-moz-fit-content;width:fit-content}.rm-lang--horizontal{grid-auto-flow:column;grid-template-rows:1fr}.rm-lang__thumb{background:var(--rm-shell-surface,var(--bg-surface));border-radius:9999px;box-shadow:0 1px 4px rgba(var(--shadow-rgb,30 41 59),.16);height:32px;left:3px;position:absolute;top:3px;transition:transform .26s cubic-bezier(.34,1.56,.64,1);width:32px}.rm-lang__option{align-items:center;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:none;border-radius:9999px;box-shadow:none;cursor:pointer;display:flex;filter:grayscale(1);height:32px;justify-content:center;margin:0;opacity:.5;padding:0;position:relative;transition:filter .18s ease,opacity .18s ease;width:32px}.rm-lang__option:hover{filter:grayscale(0);opacity:.85}.rm-lang__option--active{filter:grayscale(0);opacity:1}.rm-lang__option:focus-visible{outline:2px solid var(--rm-shell-accent,var(--color-primary));outline-offset:2px}@media (prefers-reduced-motion:reduce){.rm-lang__option,.rm-lang__thumb{transition:none}}
|
|
103
83
|
</style>
|