@edc-motor/ui 0.5.3 → 0.5.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edc-motor/ui",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "EdC Motor — componentes públicos Vue 3 + tokens SCSS para webs de juegos de mesa (paquete fuente: lo compila el consumidor con Vite)",
5
5
  "license": "GPL-3.0-only",
6
6
  "type": "module",
@@ -26,7 +26,11 @@
26
26
  bottom: 0;
27
27
  z-index: 40; // por debajo de la cabecera fija del cascarón (50)
28
28
  // En viewports mínimos deja sitio al asa (el telón cubre el resto).
29
- width: min(var(--app-right-sidebar-width), 100vw - 36px);
29
+ // OJO: 100% y no 100vw el ancho porcentual de un fixed resuelve contra
30
+ // el viewport REAL (sin la barra de scroll del navegador); con 100vw la
31
+ // scrollbar, cuando aparece, robaba su ancho y el asa/cierre quedaba
32
+ // fuera de pantalla en el tamaño más estrecho.
33
+ width: min(var(--app-right-sidebar-width), 100% - 36px);
30
34
  transform: translateX(100%);
31
35
  transition: transform 0.25s ease;
32
36
 
@@ -37,6 +37,10 @@
37
37
  }
38
38
 
39
39
  // Números de página clicables; el actual, marcado con aria-current.
40
+ // Los que NO son el actual van en caja como prev/next (fondo semiopaco +
41
+ // borde visibles ya en reposo); al hover, acento sutil: tinte de acento
42
+ // al 12% de fondo y el número en color de acento. El actual, como
43
+ // siempre: relleno de acento con texto de contraste.
40
44
  &__number {
41
45
  display: inline-flex;
42
46
  align-items: center;
@@ -44,17 +48,19 @@
44
48
  min-width: 32px;
45
49
  height: 32px;
46
50
  padding: 0 $space-1;
47
- background: none;
48
- border: 1px solid transparent;
51
+ background: color-mix(in srgb, $surface 65%, transparent);
52
+ border: 1px solid $border;
49
53
  border-radius: $radius-sm;
50
54
  color: $text-2;
51
55
  font-size: $fs-13;
56
+ // Más peso sin tocar el tamaño de la caja (32px se quedan como están).
57
+ font-weight: $k-fw-semibold;
52
58
  font-variant-numeric: tabular-nums;
53
- transition: color 0.15s ease, border-color 0.15s ease;
59
+ transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
54
60
 
55
61
  &:hover {
56
- color: $text-1;
57
- border-color: $border;
62
+ color: $accent-500;
63
+ background: color-mix(in srgb, $accent-500 12%, transparent);
58
64
  }
59
65
 
60
66
  &[aria-current="page"] {
@@ -17,6 +17,15 @@
17
17
  padding-block: 4px;
18
18
  }
19
19
 
20
+ // Variante compacta (prop compactTrigger): alto FIJO del select simple y
21
+ // resumen en una línea (el .base-select__value de arriba ya elipsa); las
22
+ // elegidas se pintan fuera (chips del consumidor), no dentro del trigger.
23
+ &--compact .base-select__trigger {
24
+ height: $input-height;
25
+ min-height: 0;
26
+ padding-block: 0;
27
+ }
28
+
20
29
  &__tags {
21
30
  display: flex;
22
31
  flex-wrap: wrap;
@@ -13,6 +13,11 @@ import type { SelectOption } from './BaseSelect.vue'
13
13
  // BaseSelect). El trigger pinta las elegidas como etiquetas con aspa: se
14
14
  // quitan desde ahí sin abrir el panel (también con Backspace); así no
15
15
  // hace falta ningún texto "N seleccionadas" que traducir.
16
+ // Con `compactTrigger` (opt-in) el trigger NO crece: mantiene el alto fijo
17
+ // del select simple y, en vez de etiquetas, pinta un resumen en una línea
18
+ // (las elegidas separadas por comas, con elipsis); quitar una elegida
19
+ // queda para fuera (el consumidor pinta sus propios chips) o para el
20
+ // propio panel/Backspace. Sin la prop, todo sigue como siempre.
16
21
  const props = withDefaults(
17
22
  defineProps<{
18
23
  modelValue?: (string | number)[]
@@ -20,12 +25,17 @@ const props = withDefaults(
20
25
  options: SelectOption[]
21
26
  /** Texto en reposo (sin nada marcado), p. ej. "Todas". */
22
27
  placeholder?: string
28
+ /**
29
+ * Trigger compacto de alto fijo: resumen en una línea (labels con
30
+ * comas y elipsis) en lugar de etiquetas con aspa dentro del trigger.
31
+ */
32
+ compactTrigger?: boolean
23
33
  error?: string
24
34
  hint?: string
25
35
  disabled?: boolean
26
36
  id?: string
27
37
  }>(),
28
- { modelValue: () => [], disabled: false },
38
+ { modelValue: () => [], disabled: false, compactTrigger: false },
29
39
  )
30
40
 
31
41
  const emit = defineEmits<{ 'update:modelValue': [value: string[]] }>()
@@ -44,6 +54,9 @@ const selectedValues = computed(() => new Set(props.modelValue.map((v) => String
44
54
  const isSelected = (option: SelectOption) => selectedValues.value.has(String(option.value))
45
55
  const selectedOptions = computed(() => props.options.filter((o) => isSelected(o)))
46
56
 
57
+ /** Resumen de una línea del trigger compacto: labels separadas por comas. */
58
+ const summary = computed(() => selectedOptions.value.map((o) => o.label).join(', '))
59
+
47
60
  /** Quita una elegida desde su etiqueta del trigger, sin tocar el panel. */
48
61
  function removeOption(option: SelectOption) {
49
62
  if (props.disabled) return
@@ -166,7 +179,7 @@ onBeforeUnmount(() => document.removeEventListener('mousedown', onOutside))
166
179
  <div
167
180
  ref="root"
168
181
  class="form-field__select-wrapper base-select multi-select"
169
- :class="{ 'is-open': open }"
182
+ :class="{ 'is-open': open, 'multi-select--compact': compactTrigger }"
170
183
  >
171
184
  <button
172
185
  :id="selectId"
@@ -180,9 +193,13 @@ onBeforeUnmount(() => document.removeEventListener('mousedown', onOutside))
180
193
  @click="toggle"
181
194
  @keydown="onKeydown"
182
195
  >
196
+ <!-- Trigger compacto (opt-in): resumen en una línea, sin etiquetas -->
197
+ <span v-if="compactTrigger && selectedOptions.length" class="base-select__value">
198
+ {{ summary }}
199
+ </span>
183
200
  <!-- Elegidas como etiquetas con aspa (el aspa NO abre el panel);
184
201
  span con role=button porque un button no puede anidar otro -->
185
- <span v-if="selectedOptions.length" class="multi-select__tags">
202
+ <span v-else-if="selectedOptions.length" class="multi-select__tags">
186
203
  <span v-for="option in selectedOptions" :key="option.value" class="multi-select__tag">
187
204
  {{ option.label }}
188
205
  <span