|
|
|
|
|
# Eidos FormatDate
|
feat(eidos): Card, Avatar ext, Image, SText, Badge, service components + dates engine fixes
Sprint completo:
- Card (eidos + sema): elevation/intent/interactive, eventos select+activate.
- Avatar: ring, AvatarBadge, AvatarGroup separados; demo Avatar standalone.
- Image: status surface (idle/loading/loaded/error) consumiendo soma ImageProvider.
- SText + STextVirtualList: canvas-text engine portado de morfo-driven-soma como
componentes separados para optimizar bundle (no se importa canvas si no se usa).
- Badge: primitivo eidos puro.
- Trans, FormatNumber, FormatDate, RelativeTime: 4 service components greppables
alrededor de uix.langs y uix.format. Nav group "Utilities".
Bugs fix arts/format/dates (engine-dates.ts):
1. Preset / per-axis conflict: Intl.DateTimeFormat rechaza dateStyle/timeStyle
con cualquier per-axis (weekday/era/year/month/day/dayPeriod/hour/minute/
second/fractionalSecondDigits) o con timeZoneName. Engine drop-ea ambos
presets por defecto cuando detecta conflict (regla estricta — un solo
per-axis hace ilegales los dos presets).
2. Per-call locale override: formatDate/Time/DateTime aceptan tercer arg
locale?: string. No muta engine state. Cache (getCachedDateFormat) keyea
por (locale x options). resolveCallHourCycle: cuando hay locale override
y pref auto, el ciclo horario se resuelve desde el locale OVERRIDE.
3. withHourCycle precedence: caller hourCycle/hour12 ahora gana sobre
preferencia del engine. Antes spread mal ordenado sobrescribia 'h12' del
caller con 'h23' del engine cuando locale resolvia a 24h.
FormatDate component vuelve a rutear siempre por uix.format.dates
(cache + hourCycle + locale reactivo), pasando locale como tercer arg.
Demos service components autonomos del toolbar global: cada uno owns su
demoLocale state con 7 chips (es-ES/en-US/en-GB/de-DE/fr-FR/ja-JP/ar-EG).
FormatDate stage filtra dateStyle/timeStyle por mode + chip hourCycle anadido.
Tests: 14/14 passing en engine-dates.test.ts (+6 nuevos: conflict handling,
locale override, hourCycle precedence).
Docs: arts/format/README.md (handoff 2026-05-25 con las 3 reglas),
README.md por service component, project_service_components_sprint_2026-05-25.md,
feedback_service_demos_own_locale.md (pattern reusable).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
|
|
|
|
|
|
|
`<FormatDate>` es un **service component** — un wrapper greppable de
|
|
|
|
|
|
`getActiveUix().format.dates.formatDate / formatTime / formatDateTime`.
|
|
|
|
|
|
Renderiza un valor `Date | number | string` a traves del runtime activo
|
|
|
|
|
|
de UIX y emite `<time datetime="ISO 8601">` por defecto para asistencia
|
|
|
|
|
|
tecnica y SEO.
|
|
|
|
|
|
|
|
|
|
|
|
Familia con `<Trans>`, `<FormatNumber>`, `<RelativeTime>`: todos son
|
|
|
|
|
|
wrappers tipados del runtime para que un audit i18n/l10n encuentre cada
|
|
|
|
|
|
sitio de formateo con `grep "<FormatDate"`.
|
|
|
|
|
|
|
|
|
|
|
|
## Superficie
|
|
|
|
|
|
|
|
|
|
|
|
```svelte
|
|
|
|
|
|
<FormatDate value={post.publishedAt} />
|
|
|
|
|
|
<FormatDate value={meeting.startsAt} mode="dateTime" dateStyle="short" timeStyle="short" />
|
|
|
|
|
|
<FormatDate value={createdAt} mode="time" timeZone="UTC" timeZoneName="short" />
|
|
|
|
|
|
<FormatDate value={anniversary} weekday="long" day="numeric" month="long" />
|
|
|
|
|
|
<FormatDate value={now} locale="ja-JP" dateStyle="full" />
|
|
|
|
|
|
<FormatDate value={start} mode="time" hourCycle="h12" />
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Props clave
|
|
|
|
|
|
|
|
|
|
|
|
| Prop | Tipo | Default | Notas |
|
|
|
|
|
|
| --- | --- | --- | --- |
|
|
|
|
|
|
| `value` | `Date \| number \| string \| null` | — | `null` o invalid → renderiza `fallback`. |
|
|
|
|
|
|
| `mode` | `'date' \| 'time' \| 'dateTime'` | `'date'` | Decide a que metodo del runtime se rutea. |
|
|
|
|
|
|
| `dateStyle` | `'short' \| 'medium' \| 'long' \| 'full'` | — | Preset. Por defecto `'medium'` cuando aplique. |
|
|
|
|
|
|
| `timeStyle` | idem | — | Preset. Por defecto `'short'` cuando aplique. |
|
|
|
|
|
|
| `weekday / era / year / month / day` | per-axis | — | Override fino. Drop-ea los presets. |
|
|
|
|
|
|
| `hour / minute / second / dayPeriod / fractionalSecondDigits` | per-axis | — | Idem para axis temporal. |
|
|
|
|
|
|
| `timeZone` | `string` | local | IANA zone (`Europe/Madrid`, …). |
|
|
|
|
|
|
| `timeZoneName` | `'short' \| 'long' \| 'shortOffset' \| 'longOffset' \| 'shortGeneric' \| 'longGeneric'` | — | Label de zona. Drop-ea presets. |
|
|
|
|
|
|
| `hourCycle` | `'h11' \| 'h12' \| 'h23' \| 'h24'` | — | Caller gana sobre preferencia del engine. |
|
|
|
|
|
|
| `calendar / numberingSystem` | `string` | — | Orthogonal a presets. |
|
|
|
|
|
|
| `locale` | `SupportedLocale` | runtime | Override por llamada. No muta el runtime. |
|
|
|
|
|
|
| `fallback` | `string` | `''` | Render cuando `value` es `null` / invalid. |
|
|
|
|
|
|
| `as` | `keyof HTMLElementTagNameMap` | `'time'` | Tag HTML. |
|
|
|
|
|
|
|
|
|
|
|
|
## Decisiones
|
|
|
|
|
|
|
|
|
|
|
|
- **Siempre rutea por `uix.format.dates`** (no llama a `Intl` directamente
|
|
|
|
|
|
excepto cuando no hay runtime). Esto preserva el cache
|
|
|
|
|
|
(`getCachedDateFormat`), la preferencia de `hourCycle` del engine, el
|
|
|
|
|
|
conflict handling, y la reactividad del locale activo.
|
|
|
|
|
|
- **`locale` se pasa como tercer arg al runtime** (`dates.formatDate(value,
|
|
|
|
|
|
options, locale)`) — el engine acepta override por llamada sin mutar
|
|
|
|
|
|
state. El cache keyea por `(locale × options)`.
|
|
|
|
|
|
- **Mode + presets**: `mode` decide a que metodo del runtime se rutea
|
|
|
|
|
|
(`formatDate / formatTime / formatDateTime`). Cada uno inyecta su
|
|
|
|
|
|
preset default (`dateStyle: 'medium'`, `timeStyle: 'short'`) solo si
|
|
|
|
|
|
no hay conflict con per-axis fields o `timeZoneName`.
|
|
|
|
|
|
- **`<time datetime="ISO 8601">` por defecto**: el ISO original queda
|
|
|
|
|
|
disponible para asistencia tecnica y crawlers. Si el caller pasa
|
|
|
|
|
|
`as="span"`, el `datetime` se aplica al span (validado por Svelte) pero
|
|
|
|
|
|
pierde la semantica nativa.
|
|
|
|
|
|
- **No CSS recipe**: el marker `[data-format-date]` existe solo para
|
|
|
|
|
|
tooling — no hay estilos a nivel de eidos porque el output es texto
|
feat(eidos): Card, Avatar ext, Image, SText, Badge, service components + dates engine fixes
Sprint completo:
- Card (eidos + sema): elevation/intent/interactive, eventos select+activate.
- Avatar: ring, AvatarBadge, AvatarGroup separados; demo Avatar standalone.
- Image: status surface (idle/loading/loaded/error) consumiendo soma ImageProvider.
- SText + STextVirtualList: canvas-text engine portado de morfo-driven-soma como
componentes separados para optimizar bundle (no se importa canvas si no se usa).
- Badge: primitivo eidos puro.
- Trans, FormatNumber, FormatDate, RelativeTime: 4 service components greppables
alrededor de uix.langs y uix.format. Nav group "Utilities".
Bugs fix arts/format/dates (engine-dates.ts):
1. Preset / per-axis conflict: Intl.DateTimeFormat rechaza dateStyle/timeStyle
con cualquier per-axis (weekday/era/year/month/day/dayPeriod/hour/minute/
second/fractionalSecondDigits) o con timeZoneName. Engine drop-ea ambos
presets por defecto cuando detecta conflict (regla estricta — un solo
per-axis hace ilegales los dos presets).
2. Per-call locale override: formatDate/Time/DateTime aceptan tercer arg
locale?: string. No muta engine state. Cache (getCachedDateFormat) keyea
por (locale x options). resolveCallHourCycle: cuando hay locale override
y pref auto, el ciclo horario se resuelve desde el locale OVERRIDE.
3. withHourCycle precedence: caller hourCycle/hour12 ahora gana sobre
preferencia del engine. Antes spread mal ordenado sobrescribia 'h12' del
caller con 'h23' del engine cuando locale resolvia a 24h.
FormatDate component vuelve a rutear siempre por uix.format.dates
(cache + hourCycle + locale reactivo), pasando locale como tercer arg.
Demos service components autonomos del toolbar global: cada uno owns su
demoLocale state con 7 chips (es-ES/en-US/en-GB/de-DE/fr-FR/ja-JP/ar-EG).
FormatDate stage filtra dateStyle/timeStyle por mode + chip hourCycle anadido.
Tests: 14/14 passing en engine-dates.test.ts (+6 nuevos: conflict handling,
locale override, hourCycle precedence).
Docs: arts/format/README.md (handoff 2026-05-25 con las 3 reglas),
README.md por service component, project_service_components_sprint_2026-05-25.md,
feedback_service_demos_own_locale.md (pattern reusable).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
|
puro.
|
|
|
|
|
|
- **No emite eventos sema**: no es una acto perceptivo del usuario.
|
|
|
|
|
|
|
|
|
|
|
|
## Conflict handling (Intl rules)
|
|
|
|
|
|
|
|
|
|
|
|
`Intl.DateTimeFormat` lanza si mezclas `dateStyle` / `timeStyle` con
|
|
|
|
|
|
cualquier per-axis field (`weekday`, `era`, `year`, `month`, `day`,
|
|
|
|
|
|
`dayPeriod`, `hour`, `minute`, `second`, `fractionalSecondDigits`) o con
|
|
|
|
|
|
`timeZoneName`. El engine drop-ea los defaults cuando detecta conflict —
|
|
|
|
|
|
**ambos presets** caen juntos porque la regla es estricta.
|
|
|
|
|
|
|
|
|
|
|
|
Si quieres mostrar timezone label (`timeZoneName`), usa per-axis:
|
|
|
|
|
|
|
|
|
|
|
|
```svelte
|
|
|
|
|
|
<FormatDate
|
|
|
|
|
|
value={createdAt}
|
|
|
|
|
|
year="numeric" month="short" day="numeric"
|
|
|
|
|
|
hour="2-digit" minute="2-digit"
|
|
|
|
|
|
timeZone="UTC" timeZoneName="short"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<!-- '25 may 2026, 14:30 UTC' -->
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Comparativa
|
|
|
|
|
|
|
|
|
|
|
|
| Capacidad | Eidos | date-fns | Day.js | luxon | Intl.DateTimeFormat |
|
feat(eidos): Card, Avatar ext, Image, SText, Badge, service components + dates engine fixes
Sprint completo:
- Card (eidos + sema): elevation/intent/interactive, eventos select+activate.
- Avatar: ring, AvatarBadge, AvatarGroup separados; demo Avatar standalone.
- Image: status surface (idle/loading/loaded/error) consumiendo soma ImageProvider.
- SText + STextVirtualList: canvas-text engine portado de morfo-driven-soma como
componentes separados para optimizar bundle (no se importa canvas si no se usa).
- Badge: primitivo eidos puro.
- Trans, FormatNumber, FormatDate, RelativeTime: 4 service components greppables
alrededor de uix.langs y uix.format. Nav group "Utilities".
Bugs fix arts/format/dates (engine-dates.ts):
1. Preset / per-axis conflict: Intl.DateTimeFormat rechaza dateStyle/timeStyle
con cualquier per-axis (weekday/era/year/month/day/dayPeriod/hour/minute/
second/fractionalSecondDigits) o con timeZoneName. Engine drop-ea ambos
presets por defecto cuando detecta conflict (regla estricta — un solo
per-axis hace ilegales los dos presets).
2. Per-call locale override: formatDate/Time/DateTime aceptan tercer arg
locale?: string. No muta engine state. Cache (getCachedDateFormat) keyea
por (locale x options). resolveCallHourCycle: cuando hay locale override
y pref auto, el ciclo horario se resuelve desde el locale OVERRIDE.
3. withHourCycle precedence: caller hourCycle/hour12 ahora gana sobre
preferencia del engine. Antes spread mal ordenado sobrescribia 'h12' del
caller con 'h23' del engine cuando locale resolvia a 24h.
FormatDate component vuelve a rutear siempre por uix.format.dates
(cache + hourCycle + locale reactivo), pasando locale como tercer arg.
Demos service components autonomos del toolbar global: cada uno owns su
demoLocale state con 7 chips (es-ES/en-US/en-GB/de-DE/fr-FR/ja-JP/ar-EG).
FormatDate stage filtra dateStyle/timeStyle por mode + chip hourCycle anadido.
Tests: 14/14 passing en engine-dates.test.ts (+6 nuevos: conflict handling,
locale override, hourCycle precedence).
Docs: arts/format/README.md (handoff 2026-05-25 con las 3 reglas),
README.md por service component, project_service_components_sprint_2026-05-25.md,
feedback_service_demos_own_locale.md (pattern reusable).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
|
| --- | --- | --- | --- | --- | --- |
|
|
|
|
|
|
| Modo `date`/`time`/`dateTime` | Si | Manual via format strings | Manual | Si (`toLocaleString`) | Manual |
|
|
|
|
|
|
| Locale reactivo desde runtime | Si | No | No | No | No |
|
|
|
|
|
|
| Cache de instancias por options | Si | No | No | No | No (creas instancia) |
|
|
|
|
|
|
| Conflict handling automatico | Si | N/A | N/A | N/A | No (lanza error) |
|
|
|
|
|
|
| HourCycle preference + override | Si | Manual | Manual | Si | No persistencia |
|
|
|
|
|
|
| `<time datetime>` semantico | Si | No | No | No | No |
|
|
|
|
|
|
| Per-call locale override | Si | Cambia DateLocale global | Manual | Manual | Si por instancia |
|
|
|
|
|
|
|
|
|
|
|
|
## Referencias
|
|
|
|
|
|
|
|
|
|
|
|
- Intl.DateTimeFormat: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat
|
|
|
|
|
|
- Engine wiring: `src/arts/format/dates/engine-dates.ts`
|
|
|
|
|
|
- Active runtime: `src/arts/format/dates/active-dates.svelte.ts`
|
|
|
|
|
|
- Conflict tests: `src/arts/format/dates/test/engine-dates.test.ts`
|