Componentes · Ola 4 · Editorial
Highlight
Las coincidencias de una búsqueda dentro de un texto, con el fondo de la selección; sin distinguir mayúsculas ni tildes. Conserva el texto original, con sus tildes y mayúsculas, y hereda la letra del texto que lo rodea.
import { Highlight } from '@archeblack/ui';
Ejemplos
Resultados de búsqueda
Escribe en el campo: el buscador filtra los posts y, en los que quedan, el título y la bajada marcan las coincidencias. El filtro es del producto; Highlight solo marca. Las filas son un IndexList listing. En Hermes, la selección es su acento.
- El Doctor que Bailó con el Tiempo Por qué el Undécimo Doctor elige el juego después de novecientos años de peso. La ligereza como pedagogía del alma, no como evasión.
1 resultado
<script lang="ts">
import '@archeblack/ui/products/hermes.css';
import { Field, Highlight, IndexList, IndexListItem, Input } from '@archeblack/ui';
let query = $state('bailo');
// Títulos y bajadas de Hermes.
const posts = [
{
title: 'El Alma Pide Locura',
slug: 'el-alma-pide-locura',
dek: 'Hay caminos fuera del jardín. Sobre la sed que el saber no calma, y la disposición que el alma estaba pidiendo.'
},
{
title: 'El Doctor que Bailó con el Tiempo',
slug: 'el-doctor-que-bailo-con-el-tiempo',
dek: 'Por qué el Undécimo Doctor elige el juego después de novecientos años de peso. La ligereza como pedagogía del alma, no como evasión.'
},
{
title: 'Lo Numinoso en CONTROL',
slug: 'lo-numinoso-en-control',
dek: 'Lo sagrado también habita en los videojuegos. Un recorrido por CONTROL: arquetipos, mandalas y el momento en que Jesse reconoce su propia voz.'
}
];
/** Sin mayúsculas ni tildes, la misma regla que usa Highlight para marcar. */
const fold = (text: string) =>
text
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLocaleLowerCase();
// El buscador filtra; Highlight solo marca lo que coincide en los resultados que quedan.
const results = $derived(
query.trim() === ''
? posts
: posts.filter((post) =>
[post.title, post.dek].some((field) => fold(field).includes(fold(query.trim())))
)
);
</script>
<!-- Resultados de búsqueda: el buscador filtra los posts y Highlight marca las coincidencias en
los que quedan. Las filas son un IndexList variant="listing": el título en 17 px semibold y la
bajada en Piazzolla; el resaltado hereda el peso de cada uno. Empieza con «bailo», que marca
«Bailó»; prueba «TIEMPO» o «alma». -->
<div data-product="hermes" style="display: grid; gap: var(--arche-spacing-6); width: 100%">
<div style:width="min(100%, 20rem)">
<Field label="Buscar">
<Input bind:value={query} type="search" />
</Field>
</div>
{#if results.length > 0}
<IndexList variant="listing" aria-label="Resultados">
{#each results as post (post.slug)}
<IndexListItem href={`#${post.slug}`}>
{#snippet title()}<Highlight text={post.title} {query} />{/snippet}
{#snippet description()}<Highlight text={post.dek} {query} />{/snippet}
</IndexListItem>
{/each}
</IndexList>
{:else}
<p style="margin: 0; color: var(--arche-color-text-muted)">
Sin resultados para «{query.trim()}».
</p>
{/if}
<p
role="status"
style="margin: 0; font-size: var(--arche-font-size-xs); color: var(--arche-color-text-subtle)"
>
{results.length === 1 ? '1 resultado' : `${results.length} resultados`}
</p>
</div> Varias búsquedas
Con una lista, se marcan todas.
¿Puede una IA tener daimon? Un ensayo desde adentro, atravesando Westworld, Her, Ex Machina y el inconsciente colectivo de Jung.
<script lang="ts">
import { Highlight } from '@archeblack/ui';
</script>
<!-- Varias búsquedas a la vez: se marcan todas. Sin tildes ni mayúsculas en la búsqueda, el texto
conserva las suyas. -->
<p style="margin: 0; max-width: 40rem; font: var(--arche-typography-reading)">
<Highlight
text="¿Puede una IA tener daimon? Un ensayo desde adentro, atravesando Westworld, Her, Ex Machina y el inconsciente colectivo de Jung."
query={['daimon', 'inconsciente', 'jung']}
/>
</p> Props
| Prop | Descripción |
|---|---|
text string | El texto que se muestra (un título, una bajada). Se escribe como texto, nunca como HTML: no hace falta sanearlo. |
query string | string[] | Lo que se busca. Cada coincidencia va en un <mark>, sin distinguir mayúsculas ni tildes («bailo» marca «Bailó»). Con varias búsquedas se marcan todas y las que se tocan se unen. Vacía o solo espacios, no marca nada. |
class? ClassValue | Se suma a arche-highlight. |
...rest HTMLAttributes | Van al <span> que envuelve el texto (lang, id…). |
Accesibilidad
- Cada coincidencia es un
<mark>: algunos lectores de pantalla anuncian «resaltado» al entrar y al salir. El texto se lee entero y en orden. - El resaltado es el fondo de la selección con
on-selected(D8b): en Arche, el vacío sobre blanco; en Hermes, sobre su acento, a más de 7:1. - En colores forzados toma
MarkyMarkText, los colores del sistema para el texto resaltado. - Hereda la letra y el peso del texto que lo rodea: no cambia el ancho de las palabras ni mueve las líneas al escribir.
Qué evitar
- Armar el resaltado con
{@html}y un reemplazo con expresiones regulares.Highlight: escribe el texto como texto y no depende de sanear la búsqueda. - Un color nuevo, un subrayado o una negrita para las coincidencias. El fondo de la selección, el mismo del
<mark>deProse(D8b). - Distinguir tildes: «bailo» que no encuentra «Bailó». La regla de
Highlight, la misma del filtro deCombobox: sin mayúsculas ni tildes.