|
|
2 months ago | |
|---|---|---|
| .. | ||
| README.md | 2 months ago | |
| index.ts | 3 months ago | |
| label.css | 2 months ago | |
| label.svelte | 2 months ago | |
| types.ts | 2 months ago | |
README.md
Label
Standalone accessible label primitive — a native <label> you can associate
with any control by id. Ported from the legacy terra/label (which mirrored
Radix Label) into the current eidos-native leaf shape.
<script lang="ts">
import { Label } from '$uix/eidos/components/label';
</script>
<Label for="email">Email address</Label>
<Label size="lg" weight="semibold" for="title">Title</Label>
<input id="email" type="email" />
Carries the foundation label typography style (--style-label-*: UI family,
sm size, medium weight, content-primary), overridable per-axis via size /
weight / color. Its only behaviour is a mousedown guard that stops a double /
triple click from selecting the label text (the Radix convention); a single
click still labels + focuses the control.
Baseline
No Air baseline. Ported from morfo-runtime:src/uix/terra/label — a
LabelProviderState that rendered <label>, passed for through, stamped
data-label, and carried the multi-click select guard. The port drops terra's
provider-state layer: in the current architecture a <label> is an
eidos-native leaf (native element, no ARIA widget, no composition, no complex
behaviour), and the visual axes follow the Text typography primitive
(--style-{name}-* base + per-instance --_{comp}-* overrides). The
select-guard is DOM hygiene, so it lives inline in the eidos wrapper.
Comparativa
| Feature | Radix | Bits UI | React Aria | Ark UI / MUI | UIX |
|---|---|---|---|---|---|
| Standalone label primitive | ✅ Label.Root |
✅ Label.Root |
✅ <Label> |
❌ field-scoped only | ✅ <Label> |
size / weight / color axes |
❌ unstyled | ❌ | ❌ | ⚠️ | ✅ Text mechanism |
| Multi-click text-select guard | ✅ onMouseDown |
✅ (from Radix) | ❌ | ❌ | ✅ inline handler |
| Field-scoped auto-wired label | ⚠️ separate | ⚠️ | ✅ context | ✅ | ✅ Field.Label |
| Floating label | ⚠️ CSS | ⚠️ | ✅ | ✅ variant | ⏳ Field concern (deferred) |
Radix and Bits ship a standalone Label; Ark UI / MUI only expose a Field-scoped
label. UIX ships both and they are complementary: <Label for="…"> for a
control outside a Field, <Field.Label> inside one (it auto-wires
for=inputId and reflects the field's invalid / disabled state).
Decisiones
- Eidos-native leaf (
scope: ['eidos'], no soma, no sema). A<label>is native HTML with no ARIA widget pattern, no part composition and no complex behaviour — it fails all three soma membership criteria. The morfo is the contract (one Provider part →data-label); the eidos wrapper stamps it and renders the<label>directly. - Follows the
Texttypography mechanism, notLink. Visual props (size/weight/color) resolve throughActiveEidos.resolve()into inline--_label-*variables over the foundation--style-label-*base — identical to how<Text style="label">works. No per-size recipe tokens (Text/Label register nobase.tsrecipe). This is why the standalone Label exposes real, selectable visual axes rather than being a prop-less shell. - The select guard stays inline in the eidos wrapper. It is stateless,
non-semantic DOM hygiene — mounting a soma provider for one handler would
violate Simplicity First. The wrapper composes the consumer's
onmousedown(if any) after its own guard, so nothing is clobbered. LabelvsField.Label. Kept as two components (as terra did):Labelis context-free with a manualfor;Field.Labelauto-wires through the field context. Neither replaces the other. Note the weights differ by design — standaloneLabeluses the foundation label weight (medium);Field.Labeloverrides toregularfor form-field density. Passweight="regular"to match.
Talla y tema
Guard R-5.4 (npm run theming:sentinel -- label <url>): 1/2 en vivo; el
otro está adjudicado con su medición en
scripts/theming-sentinel-exceptions.ts. Corrido 2026-08-22.
Contrato en lib/recipes/base.ts > label (2 claves, fusionadas con el forward
de paleta). Alcance del censo: 100 % (era 0 %).
Seis de sus ocho knobs son SISTEMA y no se acuñan. label es uno de los
seis primitivos tipográficos: sus seis ejes consumen --style-label-* a través
de la escotilla por instancia (var(--_label-{eje}, var(--style-label-{eje}))),
que es la forma que D-TH.2-b fijó y la que hace que un <Label> y un
<Text style="label"> se lean idénticos. La capa los posee.
Quedan dos knobs propios, los que el primitivo añade por su cuenta: el
gap al icono o indicador que puede acompañar al texto, y disabled-fg, la
tinta cuando el consumidor marca la etiqueta como deshabilitada junto a su
control. --_label-color sigue privado: es el conmutador de dos fuentes (eje
de tinta en línea / forward de paleta cuando llega data-color), el mismo
patrón que en code, textarea, spinner y skeleton.
Gaps
| Capability | Disposition | Notes |
|---|---|---|
Floating label (float) |
diferir | A floating label needs the control's focused / filled state, which a context-free <Label> cannot observe. It belongs to Field as a labelPlacement="floating" mode (CSS :focus-within + :placeholder-shown), reusing Field.Label. Deferred to that work — not a prop on standalone Label. |
align / truncate / italic-underline |
diferir | The Text primitive already covers rich typography; add to Label only on a real request. Implementar if a label needs them. |
invalid state token |
diferir | Field.Label reflects field-invalid via context; a standalone label has no field, so data-disabled is enough for now. |
| Soma provider for the select guard | descartar | Over-engineering for one stateless handler (see Decisiones). |
Passive justification
Label declares 0 semantic events — it is a passive display primitive. A label
neither commits, emerges, nor transitions; the perceptual events belong to the
control it labels (which carries its own sema), not to the label. Same
justification as separator.ts / link.ts. scope therefore excludes sema.
Anatomy
| Part | Element | Notes |
|---|---|---|
Label (Provider) |
<label data-label> |
Native label; for associates it with a control by id. |
Props: size (xs–xl), weight (regular/medium/semibold), color
(subtle/muted/disabled/on-solid — the content-ink axis — plus any role /
intent / donor scale / raw CSS colour) — all ResponsiveProp — plus every
HTMLLabelAttribute (for, id, class, aria-*, event handlers). Set
data-disabled when the associated control is disabled for the muted treatment.
Accessibility
- Native
<label>— full built-in label semantics, no ARIA needed. for="{id}"ties the label to a control; clicking it focuses / toggles the control.- The multi-click mousedown guard prevents accidental text selection while keeping single-click activation.
- Inside a
Field, preferField.Label— it wiresforautomatically and reflects invalid / disabled field state.