astra
alpha-0.1-background
alpha-0.1-dir-prefs
alpha-0.1-sec-dom
menubar-v4-safe
active-uix
morfo-runtime
morfo-driven-soma
semantuix
glm-5
main
sium-v1.0
${ noResults }
12 Commits (468a9d1134d697546f1b36231d6773d6324a5faa)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
e31ac3ce35 |
chore(gate): scripts/ entra en el comprobador de tipos y debe cero como src/; fuera csstype, esm-env y generate:contracts-docs; prettier ignora web/ y .claude/ (F5 del cierre, parte 1)
Preparación del formateo de una sola vez, en un commit aparte para que ese commit sea formato puro y quepa en .git-blame-ignore-revs. - scripts/ nunca se había tipado. svelte.config.js lo añade al include de Kit; tsconfig.json excluye las sondas de agentes (scripts/__*: el exclude de la raíz pisa el que genera Kit, por eso va ahí). Medido: 7 errores en 4 scripts, todos de tipos. Arreglados sin casts nuevos: tres casts que el compilador rechazaba (component-audit, docs-vocabularies) y un Set tipado estrecho (morfo-vocabulary-check, 3 errores) — el JavaScript que emite esbuild para esos tres scripts es byte-idéntico antes y después. add-contracts-imports.ts es una migración muerta (apunta a $terra, capa borrada): sus 2 errores se arreglan (index ?? 0, e instanceof Error) y borrarla es decisión del autor. - check-gate.ts: src/ y scripts/ deben cero (un ledger no puede absolverlos). Visto fallar: con un cast roto en docs-vocabularies, exit 1 «src/ and scripts/ owe zero»; restaurado byte a byte. - package.json: fuera generate:contracts-docs (su script no existe) y las dependencias csstype y esm-env, que nadie importa (esm-env sigue como transitiva de kit y svelte; npm ls lo confirma). - .prettierignore: web/ (árbol congelado) y .claude/ (configuración de la herramienta, incluido settings.local.json del autor). Verificación: check:gate OK (89 de web/ dentro del ledger; src/ y scripts/ a cero) · morfo:vocabulary exit 0 · docs:check 0/0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
3 weeks ago |
|
|
834e6c49a0 |
feat(apps): apps/base — la primera app que consume UIX como fuente desde un workspace, y su check entra en el gate (F3 del cierre)
Hasta hoy ninguna app consumía el framework fuera de su propio árbol de demos, y por eso la receta del boot pudo estar rota en producción sin que nadie lo supiera. apps/base es un esqueleto SvelteKit con adapter-static estricto y prerender, que sigue docs/consuming.md al pie de la letra: alias por resolveUixAliases, runas por config, raíz standalone (createActiveUix + setActiveUix + Soma + ActiveEidos con applyDom), boot compilado con SU esquema (es/en/ar), CSP por hash con el artefacto propio, fuentes y sonidos copiados al static/ de la app (assets:sync, con --check). La página es un AppShell con un Toggle de modo, un Select de idioma y un Dialog. Raíz: workspaces ["apps/*"] (una sola copia de svelte 5.55.0, vite 7.3.1, kit 2.55.0 y esbuild 0.27.4; lock +23 líneas); apps:check = check + build + smoke de la app, dentro del gate justo antes de la suite; .gitignore y .prettierignore para lo generado y lo copiado. El smoke sirve build/ por HTTP y pasa tres visitantes (es-ES, ar-EG, es-ES con modo oscuro y movimiento reducido), cada uno con los módulos abortados (sellos del boot) y con carga completa (0 pageerror, 0 console.error, 0 violaciones CSP, delta 0 entre boot e hidratación). Comprueba además que el tag del boot va DESPUÉS del <meta> CSP: encima, corre sin política y Kit no lo avisa. Constructor, adversarial y dos rondas de cierre (Opus). El adversarial escribió una segunda app solo con el contrato y la hizo arrancar en Chromium, Firefox y WebKit; midió la CSP en siete variantes y tres motores, y mutó la app para ver si el smoke muerde. Defectos cerrados: - D1: el smoke prometía contar traducciones ausentes y en una build de producción no hay señal (engine-langs las emite solo en DEV). Ya no lo promete; README y consuming §8 dicen dónde se ve cada cosa. - D2: el smoke nunca abría modo oscuro. Tercer visitante con el valor afirmado; un pin 'light' olvidado en la raíz ahora da exit 1. - D3: sin reset de documento el Dialog medía 409 px en un móvil de 375. La app lleva su reset de tres reglas (doctrina vigente: el reset es de la app); que la fundación lo traiga es fila del ledger. - D5: los textos del esqueleto seguían en castellano bajo lang=ar. Salen de src/lib/strings.ts por langs.ts(record), tipados. - D6: esa garantía de tipo la sostenía una unión de idiomas escrita a mano. Ahora hay UNA tupla (APP_LANGUAGES en prefs-schema.ts) que leen el esquema, los textos y el Select. Visto fallar: con 'fr' en la tupla, check exit 1 con 8 errores que nombran fr; restaurado byte a byte. - C1-C3: el contrato gana el tsconfig mínimo medido (rewriteRelativeImportExtensions, sin él 578 errores), las rutas de import de Soma/ActiveEidos/createThemeBaseEidosConfig y adapter-static + prerender. Cero cambios en src/**. Huecos del framework que la app destapa, al ledger: el Dialog modal no devuelve el foco al trigger (queda en BODY en los 3 motores: FocusScope enfoca mientras HideOthers aún tiene el inert), Select.Value muestra el value crudo hasta abrir el popup, los catálogos de componentes no tienen 'ar', la foundation se carga dos veces (482 KB enlazados + 426 KB inyectados por applyDom, 5 153 tokens duplicados), guide.md llama eidos.listThemes() dentro del hook, la regla 6 de active-uix.md está caducada, y uix.langs no lleva el tipo del catálogo de la app. Verificación: apps:check exit 0 (1391 ficheros 0 errores · build · smoke `boot 27/27 · unguarded 0 · pageerror 0 · console.error 0 · csp 0 · delta 0 · flips 0`) · boot de la app 15 365 B, byte-idéntico en dos compilaciones, su hash en el <meta> de build/index.html · docs:check 0/0 en 820 docs. Sobre el lote antes de D6 (D6 no toca src/, scripts/ ni la suite): gate entero exit 0 en 357 s, check:gate 89 dentro del ledger, suite 464/464 ficheros · 5442/5442 tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
3 weeks ago |
|
|
29e581c721 |
feat(active-uix)!: el boot lo compila el build del SITIO con su propio esquema, y lo que UIX escribe en <html dir> lleva marca de propiedad (fila 2 del boot, F1 del cierre)
F1 del plan de cierre del framework. Cierra el último trabajo del eje boot.
EL DEFECTO. El boot por defecto compilaba un catálogo de preferencias de UN
solo idioma (createDefaultUixPrefsSchema), y la raíz sembraba su entorno
leyendo el <html dir> que el boot acababa de escribir: un usuario árabe de
una app multiidioma no veía un parpadeo, se quedaba en LTR TODA la sesión,
porque el runtime tomaba la salida del boot como si la hubiera declarado la
página.
EL COMPILADOR POR SITIO. Una sola fusión, composeUixPrefsSchema, la consumen
createActiveUix y el boot: no puede derivar. El generador acepta --schema y
--out (el especificador boot/boot-schema.ts apunta al esquema del sitio o a
boot/default-schema.ts); los guards (sin runas, techo de tamaño, ASCII, sin
</script, valores string por atributo) son errores del COMPILADOR con mensajes
para el consumidor, porque ahora el artefacto lo produce el sitio. Un esquema
que importa el barrel $prefs se rechaza nombrándolo. scripts/uix-boot-check.ts
es el guard de rancidez: plugin de Vite que tumba el build con un artefacto
viejo (probado con vite build real) y función para CI. Delta cero por esquema:
por defecto, multiidioma con árabe, ejes redefinidos y esquema parcial.
LA MARCA DE PROPIEDAD, diseño firmado por el autor. El canon de dirección dice
que <html dir> es una proyección y nunca una fuente, con una sola excepción: el
dir del AUTOR en la plantilla o el servidor. El boot rompió la premisa de esa
excepción. Todo lo que UIX escribe en <html dir> lleva ahora
PREFS_DIR_PROJECTED_ATTR (el boot con valor «boot», cada proyección del runtime
con un token de instancia); la semilla solo adopta un dir SIN marca. Un dir
escrito por script no es una fuente: en ejecución la dirección se afirma con
prefs.setIntent('direction') o options.prefs.environment, que ganan a la
semilla. Se descartaron, midiendo, la marca con valor (cierra el script y
congela la dirección al navegar entre layouts) y la inferencia por valor.
dispose solo retira lo que todavía es SUYO: SvelteKit crea la raíz del layout
nuevo ANTES de destruir la vieja (medido), y un retiro a ciegas dejaba el
<html> de la raíz nueva sin dir, lang ni data-motion/sound/haptic (medido hoy:
los nueve atributos a null). Mismo principio que el unstamp de sema, que
comprueba data-event-id.
esbuild se declara como devDependency EXACTA 0.27.4: los bytes del boot y su
hash dependen del minificador, y una subida dentro de un rango rompería la
sincronía. Boot 15 198 B, sha256-hsqdGYcrRu3oEc0Q3G/A67ApQT3q9c/vT9zMDgxROg8=
(el hash se mueve: firmado por el autor).
VERIFICACIÓN. Constructor Opus en cuatro rondas y adversarial Opus en dos
pasadas independientes, con sus reproducciones repetidas tras cada cierre:
en Chromium, entrar en árabe y pasar a inglés y a español sigue al idioma, y al
revés también; el dir de plantilla gana antes y después de hidratar y en una
raíz recreada; una raíz recreada sobre una viva sigue al idioma con y sin boot;
tras create b → destroy a, <html> conserva lo que proyectó b. Diez defectos
declarados por el adversarial, cerrados (D1–D10): marca de propiedad, esquema
parcial que estampaba "undefined", vigilante de dev mudo, plugin sin test,
receta de CI que no cargaba en jsdom, cifras y prosa, y un vite build real que
se cae cuando el boot no compila. Mutaciones en rojo, restauradas byte a byte:
la proyección no marca · dispose sin guard de dueño (también repetida por el
coordinador: 3 rojos) · la semilla compara valor en vez de presencia · marcar
el dir del autor. Suite entera 463 ficheros / 5 437 tests, exit 0 · check 0 errores en src/ y en scripts/ (89 en web/, ledger intacto) ·
docs:check 0/0 · generate:boot dos veces byte-idéntico.
LO QUE NO CIERRA (al ledger de cierre): (1) PREEXISTENTE — en la misma
navegación entre layouts, el ActiveEidos.dispose de la raíz vieja sigue
retirando data-theme/mode/density/scaling de la raíz nueva; exige cambiar el
dispose de eidos, otra capa. (2) La propiedad de los atributos proyectados
cuelga de la marca de dir: si la plantilla declara la dirección, dispose deja
lang y data-motion puestos cuando la raíz se desmonta sin sustituta
(benigno). (3) Sin boot, un script que escribe dir antes de la primera raíz es
indistinguible de la plantilla y se adopta. (4) El vigilante de dev no
reacciona a ficheros nuevos ni a inputs fuera del root.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
3 weeks ago |
|
|
b55ca6eecb |
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
F2 — lote mecánico (13 ítems): - DEP-2 ogl eliminado (0 imports) · DEP-1 clsx inlineado como toClassString propio + suite de contrato (props.test.ts; soma.md §12 cerrado). - THM-7: los 5 selectores manuales de sema.md reescritos con semaSelector (los ejemplos [data-toast-root] apuntaban a un part INEXISTENTE — la deriva que el builder previene, demostrada en el propio doc). - MOR-1 escape isomorfo + validación de attr-names en semaSelector + 9 tests (selectors.test.ts, matches() real con comillas/corchetes) · MOR-2 partMarkerAttr = única fuente compilador↔builder + test de paridad · MOR-3 _resetCompileCache borrado (0 usos). - SOM-2 keydown continue en match sin handler + keyboardFixtureMorfo · SOM-1 no-await de handlers (censo async = 0; contrato V1 cumplido) + pin. - SEM-2 trigger pre-attacha catch con logger (void trigger sin unhandled rejection; throw intacto para awaiters) + pin · SEM-3 fallback muerto de applyDominance → skip defensivo + timer tope de awaitExpression cancelado · SEC-1 adjudicado YA implementado (assertCssVariableValue desde 2026-05-11) + pin del path de VALOR. - accordion → outline (§32; su outline:none dejaba CERO anillo en HCM) — verificado en vivo · THM-6 radius-full 9999px · EID-4 recuentos 33. F3 — censos con guard: - SOM-3 cerrado: announcer + image-provider migrados a scheduler-preferred (consumidores cableados: date/time-field vía soma.uix.timers; avatar/image vía eidos.timers — verificado en vivo); guard de timers ENSANCHADO de soma/components a TODO soma y pasado a EVIDENCIA (setTimeout exige .schedule( en el fichero — layers/ y datetime/ escapaban del ámbito viejo). - THM-5: R-4.7 nueva (válvula same-line /* important: <razón> */, escaneo comment-blanked) + las 15 declaraciones anotadas con su razón + canon recipe-contract §3/§4. - SOM-4 adjudicado: el censo/guard YA existían (49 pins); knob/mask-field/ timeline pinneados (overrides documentados en call-site); media-player Batch-4 (35 hits, cero renderProps) = único batch restante, registrado. - THM-4 doctrinado en eidos.md §unused (comportamiento/composición = legítimo; deuda = eje visual sin consumidor; hotspots por lotes). F4-C — corpus documental (decisiones de usuario aplicadas): - DOC-3: los 15 enlaces muertos resueltos (repoint a la edición FINAL trackeada / des-link históricos) · docs:check I6-links WARN→ERROR. - DOC-1: tabla «Build contract» MIGRADA a component-guide con estados modernizados (A3–A5 → LIVE + guards de hoy); banners reapuntados; citas de CANON/sema.md historificadas; lápida-redirect en el §13 del fósil. - DOC-4: hold chain → holds.ts · FAQ event:* SUPERSEDED por signatures · gradient añadido a los DOS capstones (sextet real) · nota de paleta de demo-authoring corregida (universalPaletteDecls + decisión THM-2 = mecanismo universal como sucesor del tracker borrado). - DOC-5/6: recuentos anti-frágiles datados · §4.11 dup → §4.12 · Known gaps historificado · N-6/N-7 recuperadas de git (d68d2c45^) y canonizadas en eidos.md §pickers · authoring E2 → canon/tsc.md · air-old des-linkado · EID-3 (placement) en la fila RTL · AUX-2 disabledDom documentado. SEM-4 sesión 1 — el close polimórfico de los pickers, VIVO (D.11): - Reconciliación: los morfos ya no declaran close (delegated al Popover, de-dialoged 06-27); el agujero real era el cierre programático bypaseando dismissWith → save/cancel/select eran perceptualmente SILENCIOSOS. - Fix: PickerShellHandle.setPopoverDismiss + closeWith(cause) en los 5 providers (14 sitios; select/commit → 'save' = commit.save+fulfill, cancel → 'cancel' = emerge; fallback raw para headless) + UN inyector en el eidos PickerShell root (norma N-8). Picker genérico fuera a propósito (ya suena commit-set/cancel por diseño S9). - Verificado en vivo (date-picker): Done → close·commit·fulfill·active · Cancel → close·emerge · cierre real. Gates: matriz 141/141 (los 6 morfos nuevos de la pista de texto paralela también PASS) · contracts 38/38 · eidos 314 · sema 178 · morfo 94 · docs:check 0/0 con I6 en error · baseline propio 57. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
d0f41fb21a |
refactor(libs): own port of runed + tabbable — drop 2 runtime deps (F1+F2)
Removes the two runtime dependencies that broke the "framework depends on nobody" doctrine, porting them into our own code (same move as floating-ui -> $ethereal). F1 (dropped the deps): - tabbable -> src/libs/dom/tabbable-core.ts (getComputedStyle/CSS.escape resolved from the node's own window, iframe-safe); consumed by the existing tabbable.ts wrapper and surfaced via $adom. - runed Context + watch/watch.pre/watchOnce -> $libs/reactive. - runed ElementSize -> $adom/element-size.svelte.ts, rebuilt window-correct on the node's own window (not defaultWindow). - Rewired ~33 watch + 3 Context imports; floating (ElementSize) and focus-scope (tabbable) now consume $adom. F2 (rest of the pure reactive runes -> $libs/reactive): - Previous, IsMounted, onCleanup, interval, debounce/Debounced, throttle/Throttled, StateHistory, FiniteStateMachine, resource. - Dropped runed's React-style use* prefix; reused framework toValue (=extract) + MaybeActiveOrGetter; added Setter<T>. runed + tabbable removed from package.json. `npm run check` = 59 (baseline, 0 in ported files); tests unchanged (pre-existing failures only). F3 (remaining DOM-reactive runes -> $adom on ActiveDom, + PersistedState -> $storage) is pending: see docs/process/continue-runed-tabbable-port.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
56eb9bd265 |
feat(ethereal): finalize — own engine is the runtime + dual-engine native path
Two parts: the cutover (own JS engine replaces @floating-ui as the runtime, dep out of the library) and the native CSS Anchor Positioning path layered on top. Cutover (P4, reconciled): - Flip USE_OWN_ENGINE -> true, then delete it (flag.ts removed). Collapse the A/B in use-floating + floating.svelte to own-only (drop the fui imports, the factory shim, the `as unknown as` casts). useFloating's `dom` is now required. - @floating-ui moved dependencies -> devDependencies: the LIBRARY (src/arts/ethereal + src/uix/soma) imports it NOWHERE; it stays only for the visual demo + the parity oracle. Zero-dep doctrine met for consumers. Dual engine (P2 — built + proven end-to-end): - `selectPositioningStrategy` ($ethereal/strategy.ts, 5 tests) picks native vs JS per instance on discriminators (arrow / shift / virtual-anchor / explicit-boundary; sticky is subsumed by shift). The behavioural twin of supportsCssAnchor. - eidos `renderFloatingNativeBlock`: @supports (anchor-name) and (position-area) with position-area from data-side/align (logical axes — validated against the spec), per-side gap margin, position-try-fallbacks for flip. base.css regenerated. - soma wrapper: when native, stamps data-floating-native + an inline anchor-name<-> position-anchor link and PAUSES the JS positioner (no computePosition, no autoUpdate). - New `avoidCollisions: 'flip'` (flip-only, no slide) decouples flip from shift so an overlay can flip natively. Popover demo: avoidCollisions = full / flip / off. - Proven in a real browser: a flip-only arrowless popover routes to native, positions via position-area, and flips natively (flip-block) at an edge — zero JS transform. Honest scope: shift has no native primitive, so native lights up only for non-shift overlays; the JS engine stays the default for collision-avoiding ones. data-side doesn't track a native flip, so native is gated to the arrowless case. Verified: 537 tests green (ethereal + 7 overlays + floating + generated-css), 0 new check errors. Docs: CONTINUE.md, PERF.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
8f84b36f6d |
feat(eidos): field-family font-scaling coherence (input 1:1 + label step-down)
- Field font scale: input 1:1 (size N -> --font-size-N, md now 16px), label one step below (10/12/14/16/18). Recipes: field, spin-field, date/time/color-field, search-field, password-field, select, editable, tags-input. Segmented-field labels via CSS calc; generic Field label via label-font-size tokens. - Picker triggers (date/time/range): box now scales off the local --_X-field-height + font:inherit so the 1em icon follows the field font; added the missing xs size variant to time-picker + time-range-picker. - color-field/time-field commit-set fires + sounds on increment (compare by ColorValue.hex; time-field passes fallbackTarget for the double-registered 'input' part). - color-field format-select: reverted the segment-active tint back to its focus ring. - Docs: THEMING.md field font rule; COMPONENT_COHERENCE_AUDIT.md. words / palabras / chronos untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
4 months ago |
|
|
f07addf07b |
soma: tier 1/2 components, Field/NumberField integration, codex_audit fixes
New components: context-menu, field, file-upload, link-preview, menubar. Codex audit fixes (2026-04-17): - Wrappers thinned: table, scroll-area scrollbar, calendar, range-calendar - Toast Root → Item refactor (data-toast-item, resolves part collision) - TreeView tab-stop fallback, Table right-pinned offset, Toolbar O(N) registry - Combobox label registry, Pagination count=0, Splitter feasible-range clamp - TagsInput relatedTarget, Toast compound hotkey, RadioGroup closest filter - Accessible-name props (aria-label/-labelledby) tipados en RadioGroup/Slider/ Switch/Toolbar; Slider thumbLabels per-index - NumberField startValue saneado, Table getIsSomeSelected filtra visibles - Docs: DropdownMenu CheckboxGroup, NumberField terra-free, Pagination First/Last snippet Supporting changes: - App layer + ling/logr/glob/util consolidation, tests updates - Terra/scripts mechanical reformat (quotes, imports) - Test pages updated to match new APIs Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
6 months ago |
|
|
978a6f3463 |
Fix Command demo with Dialog integration
- Add Command Dialog demo (⌘K style) with proper Dialog.Trigger - Make all inline demos collapsible to prevent UI clutter - Add keyboard shortcut (cmd+k / ctrl+k) for Command Dialog - Add close button (✕) and onSelect handlers to close dialog - Fix CSS import paths in air/ and terra/ test pages - Fix various syntax errors in test pages (toggle, toggle-group, meter) - Update Switch and RadioGroup contracts with missing attributes - Fix missing ctx declarations in time-field and time-range-field - Fix checkbox group import error Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
6 months ago |
|
|
9084d2783a |
feat: port Dialog to acel, refactor alert-dialog, fix TS errors, add test pages
- Port Dialog component from uisv to acel (dialog.svelte.ts state machine) - Rewrite alert-dialog as thin wrapper over acel Dialog - Remove 4 redundant alert-dialog components (Trigger, Overlay, Title, Description) now re-exported directly from dialog/components/ - Add Dialog export to acel/index.ts - Fix double-namespace in button/index.ts - Fix SPA config: ssr=false, prerender=false, adapter-static fallback - Fix Snippet<[DialogContentSnippetProps]> children call with snippetProps - Fix glob/lib/date TS errors: import type for verbatimModuleSyntax (×45) - Fix TS7053 in manipulation.ts invertDuration and DateFormatter.ts - Fix TS2322 hourCycle type in comn_utils.ts and DateFormatter.ts - Recreate test pages: accordion, collapsible, alert-dialog, dialog (new), button (new) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
7 months ago |
|
|
0dac42173e |
refactor: reestructura actx/glob/uiux, agrega librería acel y rutas de test
- Refactoriza actx eliminando nr_actx/nr_engine, unifica en engine.svelte.ts - Actualiza motores de glob (curr, dati, numr, unit) con variantes .svelte.ts - Agrega librería de componentes UI acel (accordion, button, collapsible, modal) - Configura SPA pura: ssr=false, prerender=false, adapter-static con fallback - Agrega rutas de test para accordion, collapsible y modal - Corrige doble namespace en accordion/index.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
7 months ago |
|
|
781bfb7e4b |
Initial commit: SvelteKit application with modular libraries
Add comprehensive library system for internationalization, logging, formatting, and UI state management: - ling: i18n library with translation keys, plural rules, and JSON serialization - logr: logging system with levels, filters, history, and transports - glob: number (numr), date (dati), currency (curr), and unit (unit) formatters - actx: application context integrating all modules with Svelte 5 reactivity - uiux: reactive UI state for theme, toasts, modals, menus, and breakpoints Features: - 247 passing tests across 4 test suites - Svelte 5 runes ($state) for reactive context - Lazy initialization for optional modules - Type-safe configuration with TypeScript - Locale-aware formatting using Intl APIs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
7 months ago |