|
|
<script lang="ts">
|
|
|
import { FormatNumber } from '$uix/eidos/components/format-number';
|
|
|
import { compileMorfo } from '$uix/morfo';
|
|
|
import { formatNumberMorfo } from '@/uix/morfo/components/format-number';
|
|
|
import { getActiveUix } from '$active-uix';
|
|
|
|
|
|
type Tab = 'live' | 'api' | 'morfo' | 'sema' | 'recipe' | 'a11y';
|
|
|
let tab = $state<Tab>('live');
|
|
|
|
|
|
const uix = getActiveUix();
|
|
|
const compiled = compileMorfo(formatNumberMorfo);
|
|
|
const partsList = $derived([...compiled.parts.byKebab.values()]);
|
|
|
|
|
|
// ── Live state ────────────────────────────────────────────────────────
|
|
|
// Demo owns its own `locale` state so the toolbar's global locale
|
|
|
// doesn't drag this demo around.
|
|
|
type DemoLocale = 'es-ES' | 'en-US' | 'en-GB' | 'de-DE' | 'fr-FR' | 'ja-JP' | 'ar-EG';
|
|
|
const DEMO_LOCALES: readonly DemoLocale[] = [
|
|
|
'es-ES',
|
|
|
'en-US',
|
|
|
'en-GB',
|
|
|
'de-DE',
|
|
|
'fr-FR',
|
|
|
'ja-JP',
|
|
|
'ar-EG'
|
|
|
];
|
|
|
|
|
|
let value = $state(1234567.89);
|
|
|
let demoLocale = $state<DemoLocale>('es-ES');
|
|
|
let formatStyle = $state<'decimal' | 'percent' | 'currency' | 'unit'>('decimal');
|
|
|
let currency = $state('EUR');
|
|
|
let unit = $state('byte');
|
|
|
let notation = $state<'standard' | 'compact' | 'scientific' | 'engineering'>('standard');
|
|
|
let compactDisplay = $state<'short' | 'long'>('short');
|
|
|
let signDisplay = $state<'auto' | 'never' | 'always' | 'exceptZero' | 'negative'>('auto');
|
|
|
let useGrouping = $state(true);
|
|
|
let minimumFractionDigits = $state<number | undefined>(undefined);
|
|
|
let maximumFractionDigits = $state<number | undefined>(undefined);
|
|
|
let valueAsPercent = $state(false);
|
|
|
|
|
|
const eidosSnippet = $derived(
|
|
|
[
|
|
|
"<script lang='ts'>",
|
|
|
" import { FormatNumber } from '$uix/eidos/components/format-number';",
|
|
|
'</' + 'script>',
|
|
|
'',
|
|
|
'<FormatNumber',
|
|
|
` value={${value}}`,
|
|
|
formatStyle !== 'decimal' && ` formatStyle="${formatStyle}"`,
|
|
|
formatStyle === 'currency' && ` currency="${currency}"`,
|
|
|
formatStyle === 'unit' && ` unit="${unit}"`,
|
|
|
notation !== 'standard' && ` notation="${notation}"`,
|
|
|
notation === 'compact' && compactDisplay !== 'short' && ` compactDisplay="${compactDisplay}"`,
|
|
|
signDisplay !== 'auto' && ` signDisplay="${signDisplay}"`,
|
|
|
!useGrouping && ' useGrouping={false}',
|
|
|
minimumFractionDigits !== undefined && ` minimumFractionDigits={${minimumFractionDigits}}`,
|
|
|
maximumFractionDigits !== undefined && ` maximumFractionDigits={${maximumFractionDigits}}`,
|
|
|
valueAsPercent && ' valueAsPercent',
|
|
|
'/>'
|
|
|
]
|
|
|
.filter(Boolean)
|
|
|
.join('\n')
|
|
|
);
|
|
|
</script>
|
|
|
|
|
|
<div data-uix-canvas-inner>
|
|
|
<header>
|
|
|
<div data-uix-eyebrow>Utilities · FormatNumber</div>
|
|
|
<h1 data-uix-page-title>FormatNumber</h1>
|
|
|
<p data-uix-page-lede>
|
|
|
Service component that wraps <code>getActiveUix().format.numbers</code> for locale-aware
|
|
|
number rendering. Same family as <a href="/uix/components/trans"><Trans></a> —
|
|
|
grep-friendly wrapper around the active runtime API. Reactive to locale + currency
|
|
|
changes. Sin CSS recipe — sólo el marker <code>[data-format-number]</code> para tooling.
|
|
|
</p>
|
|
|
<div data-uix-page-meta>
|
|
|
<span data-uix-meta-pill>
|
|
|
<span data-uix-meta-key>parts</span>{compiled.parts.order.length}
|
|
|
</span>
|
|
|
<span data-uix-meta-pill>
|
|
|
<span data-uix-meta-key>events</span>0
|
|
|
</span>
|
|
|
<span data-uix-meta-pill>
|
|
|
<span data-uix-meta-key>styles</span>4
|
|
|
</span>
|
|
|
<span data-uix-meta-pill>
|
|
|
<span data-uix-meta-key>locale</span>
|
|
|
<code>{uix.langs.getLocale()}</code>
|
|
|
</span>
|
|
|
<span data-uix-meta-pill>
|
|
|
<span data-uix-meta-key>scope</span>eidos
|
|
|
</span>
|
|
|
</div>
|
|
|
</header>
|
|
|
|
|
|
<!-- Live preview -->
|
|
|
<div data-uix-stage>
|
|
|
<div data-uix-stage-area>
|
|
|
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; padding: var(--uix-space-6); inline-size: 100%;">
|
|
|
<div style="font-size: var(--uix-font-size-3xl); font-weight: 600;">
|
|
|
<FormatNumber
|
|
|
{value}
|
|
|
locale={demoLocale}
|
|
|
{formatStyle}
|
|
|
{currency}
|
|
|
{unit}
|
|
|
{notation}
|
|
|
{compactDisplay}
|
|
|
{signDisplay}
|
|
|
{useGrouping}
|
|
|
{minimumFractionDigits}
|
|
|
{maximumFractionDigits}
|
|
|
{valueAsPercent}
|
|
|
/>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div data-uix-stage-trace>
|
|
|
<span data-uix-stage-trace-key>value</span>
|
|
|
<code>{value}</code>
|
|
|
<span style="color: var(--uix-text-faint)">·</span>
|
|
|
<span data-uix-stage-trace-key>style</span>
|
|
|
<span>{formatStyle}</span>
|
|
|
<span style="margin-inline-start: auto;">
|
|
|
<span data-uix-stage-trace-key>locale</span>
|
|
|
<code>{demoLocale}</code>
|
|
|
</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div data-uix-tabs role="tablist">
|
|
|
<button data-uix-tab data-active={tab === 'live'} onclick={() => (tab = 'live')}>Live</button>
|
|
|
<button data-uix-tab data-active={tab === 'api'} onclick={() => (tab = 'api')}>
|
|
|
API <span data-uix-tab-count>17</span>
|
|
|
</button>
|
|
|
<button data-uix-tab data-active={tab === 'morfo'} onclick={() => (tab = 'morfo')}>
|
|
|
<span data-uix-layer-badge="morfo">morfo</span>
|
|
|
<span data-uix-tab-count>{partsList.length}p · 0e</span>
|
|
|
</button>
|
|
|
<button data-uix-tab data-active={tab === 'sema'} onclick={() => (tab = 'sema')}>
|
|
|
<span data-uix-layer-badge="sema">sema</span>
|
|
|
<span data-uix-tab-count>0</span>
|
|
|
</button>
|
|
|
<button data-uix-tab data-active={tab === 'recipe'} onclick={() => (tab = 'recipe')}>Recipe</button
|
|
|
>
|
|
|
<button data-uix-tab data-active={tab === 'a11y'} onclick={() => (tab = 'a11y')}>A11y</button>
|
|
|
</div>
|
|
|
|
|
|
{#if tab === 'live'}
|
|
|
<section data-uix-section>
|
|
|
<h2 data-uix-section-title>Controls</h2>
|
|
|
|
|
|
<div data-uix-controls>
|
|
|
<label data-uix-control>
|
|
|
<span data-uix-control-label>value</span>
|
|
|
<input
|
|
|
type="number"
|
|
|
bind:value
|
|
|
step="0.01"
|
|
|
style="inline-size: 16rem; font-family: var(--uix-font-mono);"
|
|
|
/>
|
|
|
</label>
|
|
|
<label data-uix-control>
|
|
|
<span data-uix-control-label>style</span>
|
|
|
<span data-uix-chips role="radiogroup">
|
|
|
{#each ['decimal', 'percent', 'currency', 'unit'] as s}
|
|
|
<button
|
|
|
data-uix-chip
|
|
|
data-active={formatStyle === s}
|
|
|
onclick={() => (formatStyle = s as typeof formatStyle)}>{s}</button
|
|
|
>
|
|
|
{/each}
|
|
|
</span>
|
|
|
</label>
|
|
|
{#if formatStyle === 'currency'}
|
|
|
<label data-uix-control>
|
|
|
<span data-uix-control-label>currency</span>
|
|
|
<span data-uix-chips role="radiogroup">
|
|
|
{#each ['EUR', 'USD', 'GBP', 'JPY', 'CNY', 'INR'] as c}
|
|
|
<button
|
|
|
data-uix-chip
|
|
|
data-active={currency === c}
|
|
|
onclick={() => (currency = c)}>{c}</button
|
|
|
>
|
|
|
{/each}
|
|
|
</span>
|
|
|
</label>
|
|
|
{/if}
|
|
|
{#if formatStyle === 'unit'}
|
|
|
<label data-uix-control>
|
|
|
<span data-uix-control-label>unit</span>
|
|
|
<span data-uix-chips role="radiogroup">
|
|
|
{#each ['byte', 'kilometer', 'kilometer-per-hour', 'celsius', 'percent', 'meter', 'liter'] as u}
|
|
|
<button
|
|
|
data-uix-chip
|
|
|
data-active={unit === u}
|
|
|
onclick={() => (unit = u)}>{u}</button
|
|
|
>
|
|
|
{/each}
|
|
|
</span>
|
|
|
</label>
|
|
|
{/if}
|
|
|
{#if formatStyle === 'percent'}
|
|
|
<label data-uix-control>
|
|
|
<span data-uix-control-label
|
|
|
>valueAsPercent
|
|
|
<span data-uix-control-hint>treat value as already × 100</span></span
|
|
|
>
|
|
|
<span data-uix-switch>
|
|
|
<input type="checkbox" bind:checked={valueAsPercent} />
|
|
|
<span data-uix-switch-label>{valueAsPercent ? 'on' : 'off'}</span>
|
|
|
</span>
|
|
|
</label>
|
|
|
{/if}
|
|
|
<label data-uix-control>
|
|
|
<span data-uix-control-label>notation</span>
|
|
|
<span data-uix-chips role="radiogroup">
|
|
|
{#each ['standard', 'compact', 'scientific', 'engineering'] as n}
|
|
|
<button
|
|
|
data-uix-chip
|
|
|
data-active={notation === n}
|
|
|
onclick={() => (notation = n as typeof notation)}>{n}</button
|
|
|
>
|
|
|
{/each}
|
|
|
</span>
|
|
|
</label>
|
|
|
{#if notation === 'compact'}
|
|
|
<label data-uix-control>
|
|
|
<span data-uix-control-label>compactDisplay</span>
|
|
|
<span data-uix-chips role="radiogroup">
|
|
|
{#each ['short', 'long'] as c}
|
|
|
<button
|
|
|
data-uix-chip
|
|
|
data-active={compactDisplay === c}
|
|
|
onclick={() => (compactDisplay = c as typeof compactDisplay)}>{c}</button
|
|
|
>
|
|
|
{/each}
|
|
|
</span>
|
|
|
</label>
|
|
|
{/if}
|
|
|
<label data-uix-control>
|
|
|
<span data-uix-control-label>signDisplay</span>
|
|
|
<span data-uix-chips role="radiogroup">
|
|
|
{#each ['auto', 'never', 'always', 'exceptZero', 'negative'] as s}
|
|
|
<button
|
|
|
data-uix-chip
|
|
|
data-active={signDisplay === s}
|
|
|
onclick={() => (signDisplay = s as typeof signDisplay)}>{s}</button
|
|
|
>
|
|
|
{/each}
|
|
|
</span>
|
|
|
</label>
|
|
|
<label data-uix-control>
|
|
|
<span data-uix-control-label>useGrouping</span>
|
|
|
<span data-uix-switch>
|
|
|
<input type="checkbox" bind:checked={useGrouping} />
|
|
|
<span data-uix-switch-label>{useGrouping ? 'on' : 'off'}</span>
|
|
|
</span>
|
|
|
</label>
|
|
|
<label data-uix-control>
|
|
|
<span data-uix-control-label>minimumFractionDigits</span>
|
|
|
<input
|
|
|
type="number"
|
|
|
bind:value={minimumFractionDigits}
|
|
|
min="0"
|
|
|
max="20"
|
|
|
placeholder="auto"
|
|
|
style="inline-size: 8rem;"
|
|
|
/>
|
|
|
</label>
|
|
|
<label data-uix-control>
|
|
|
<span data-uix-control-label>maximumFractionDigits</span>
|
|
|
<input
|
|
|
type="number"
|
|
|
bind:value={maximumFractionDigits}
|
|
|
min="0"
|
|
|
max="20"
|
|
|
placeholder="auto"
|
|
|
style="inline-size: 8rem;"
|
|
|
/>
|
|
|
</label>
|
|
|
</div>
|
|
|
|
|
|
<div data-uix-code style="margin-top: var(--uix-space-4);">
|
|
|
<div data-uix-code-head>
|
|
|
<span data-uix-layer-badge="eidos">eidos</span>
|
|
|
<span>composition · all options applied</span>
|
|
|
<span data-uix-code-lang>svelte</span>
|
|
|
</div>
|
|
|
<pre><code>{eidosSnippet}</code></pre>
|
|
|
</div>
|
|
|
|
|
|
<div data-uix-subsection-head>Patterns · common shapes</div>
|
|
|
<div data-uix-pattern-stack>
|
|
|
<div data-uix-pattern>
|
|
|
<h3 data-uix-pattern-title>Decimal · plain numbers locale-aware</h3>
|
|
|
<div data-uix-pattern-row>
|
|
|
<table data-uix-table>
|
|
|
<thead><tr><th>Markup</th><th>Output</th></tr></thead>
|
|
|
<tbody>
|
|
|
<tr><td><code><FormatNumber value={'{1234567}'} /></code></td><td><strong><FormatNumber value={1234567} /></strong></td></tr>
|
|
|
<tr><td><code><FormatNumber value={'{3.14159}'} maximumFractionDigits={'{2}'} /></code></td><td><strong><FormatNumber value={3.14159} maximumFractionDigits={2} /></strong></td></tr>
|
|
|
<tr><td><code><FormatNumber value={'{-42}'} signDisplay="always" /></code></td><td><strong><FormatNumber value={-42} signDisplay="always" /></strong></td></tr>
|
|
|
<tr><td><code><FormatNumber value={'{1234}'} useGrouping={'{false}'} /></code></td><td><strong><FormatNumber value={1234} useGrouping={false} /></strong></td></tr>
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div data-uix-pattern>
|
|
|
<h3 data-uix-pattern-title>Percent · with vs without valueAsPercent</h3>
|
|
|
<div data-uix-pattern-row>
|
|
|
<table data-uix-table>
|
|
|
<thead><tr><th>Markup</th><th>Output</th></tr></thead>
|
|
|
<tbody>
|
|
|
<tr><td><code>value={'{0.425}'} formatStyle="percent"</code></td><td><strong><FormatNumber value={0.425} formatStyle="percent" /></strong></td></tr>
|
|
|
<tr><td><code>value={'{42.5}'} formatStyle="percent" valueAsPercent</code></td><td><strong><FormatNumber value={42.5} formatStyle="percent" valueAsPercent /></strong></td></tr>
|
|
|
<tr><td><code>value={'{1.5}'} formatStyle="percent" minimumFractionDigits={'{1}'}</code></td><td><strong><FormatNumber value={1.5} formatStyle="percent" minimumFractionDigits={1} /></strong></td></tr>
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div data-uix-pattern>
|
|
|
<h3 data-uix-pattern-title>Currency · ISO 4217 + display variants</h3>
|
|
|
<div data-uix-pattern-row>
|
|
|
<table data-uix-table>
|
|
|
<thead><tr><th>Markup</th><th>Output</th></tr></thead>
|
|
|
<tbody>
|
|
|
<tr><td><code>currency="EUR" value={'{1499}'}</code></td><td><strong><FormatNumber value={1499} formatStyle="currency" currency="EUR" /></strong></td></tr>
|
|
|
<tr><td><code>currency="USD" value={'{1499}'} notation="compact"</code></td><td><strong><FormatNumber value={1499} formatStyle="currency" currency="USD" notation="compact" /></strong></td></tr>
|
|
|
<tr><td><code>currency="GBP" value={'{1234567}'} notation="compact" compactDisplay="long"</code></td><td><strong><FormatNumber value={1234567} formatStyle="currency" currency="GBP" notation="compact" compactDisplay="long" /></strong></td></tr>
|
|
|
<tr><td><code>currency="JPY" value={'{12345}'} currencyDisplay="name"</code></td><td><strong><FormatNumber value={12345} formatStyle="currency" currency="JPY" currencyDisplay="name" /></strong></td></tr>
|
|
|
<tr><td><code>currency="USD" value={'{-99.5}'} currencySign="accounting"</code></td><td><strong><FormatNumber value={-99.5} formatStyle="currency" currency="USD" currencySign="accounting" /></strong></td></tr>
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div data-uix-pattern>
|
|
|
<h3 data-uix-pattern-title>Unit · bytes, distances, temperatures</h3>
|
|
|
<div data-uix-pattern-row>
|
|
|
<table data-uix-table>
|
|
|
<thead><tr><th>Markup</th><th>Output</th></tr></thead>
|
|
|
<tbody>
|
|
|
<tr><td><code>unit="byte" value={'{2048}'}</code></td><td><strong><FormatNumber value={2048} formatStyle="unit" unit="byte" /></strong></td></tr>
|
|
|
<tr><td><code>unit="byte" value={'{1500000000}'} notation="compact"</code></td><td><strong><FormatNumber value={1500000000} formatStyle="unit" unit="byte" notation="compact" /></strong></td></tr>
|
|
|
<tr><td><code>unit="kilometer-per-hour" value={'{120}'}</code></td><td><strong><FormatNumber value={120} formatStyle="unit" unit="kilometer-per-hour" /></strong></td></tr>
|
|
|
<tr><td><code>unit="celsius" value={'{-3.5}'} unitDisplay="long"</code></td><td><strong><FormatNumber value={-3.5} formatStyle="unit" unit="celsius" unitDisplay="long" /></strong></td></tr>
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div data-uix-pattern>
|
|
|
<h3 data-uix-pattern-title>Compact notation · 1.2K · 3M · 1B</h3>
|
|
|
<div data-uix-pattern-row>
|
|
|
<table data-uix-table>
|
|
|
<thead><tr><th>Value</th><th>compact short</th><th>compact long</th></tr></thead>
|
|
|
<tbody>
|
|
|
<tr><td>1500</td><td><strong><FormatNumber value={1500} notation="compact" /></strong></td><td><strong><FormatNumber value={1500} notation="compact" compactDisplay="long" /></strong></td></tr>
|
|
|
<tr><td>1234567</td><td><strong><FormatNumber value={1234567} notation="compact" /></strong></td><td><strong><FormatNumber value={1234567} notation="compact" compactDisplay="long" /></strong></td></tr>
|
|
|
<tr><td>3500000000</td><td><strong><FormatNumber value={3500000000} notation="compact" /></strong></td><td><strong><FormatNumber value={3500000000} notation="compact" compactDisplay="long" /></strong></td></tr>
|
|
|
<tr><td>1234567890123</td><td><strong><FormatNumber value={1234567890123} notation="compact" /></strong></td><td><strong><FormatNumber value={1234567890123} notation="compact" compactDisplay="long" /></strong></td></tr>
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div data-uix-pattern>
|
|
|
<h3 data-uix-pattern-title>Locale override · same value, different formatting rules</h3>
|
|
|
<div data-uix-pattern-row>
|
|
|
<table data-uix-table>
|
|
|
<thead><tr><th>Locale</th><th>Decimal</th><th>Currency (EUR)</th></tr></thead>
|
|
|
<tbody>
|
|
|
<tr><td><code>es-ES</code></td><td><strong><FormatNumber value={1234567.89} locale="es-ES" /></strong></td><td><strong><FormatNumber value={1234567.89} formatStyle="currency" currency="EUR" locale="es-ES" /></strong></td></tr>
|
|
|
<tr><td><code>en-US</code></td><td><strong><FormatNumber value={1234567.89} locale="en-US" /></strong></td><td><strong><FormatNumber value={1234567.89} formatStyle="currency" currency="EUR" locale="en-US" /></strong></td></tr>
|
|
|
<tr><td><code>de-DE</code></td><td><strong><FormatNumber value={1234567.89} locale="de-DE" /></strong></td><td><strong><FormatNumber value={1234567.89} formatStyle="currency" currency="EUR" locale="de-DE" /></strong></td></tr>
|
|
|
<tr><td><code>en-GB</code></td><td><strong><FormatNumber value={1234567.89} locale="en-GB" /></strong></td><td><strong><FormatNumber value={1234567.89} formatStyle="currency" currency="EUR" locale="en-GB" /></strong></td></tr>
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div data-uix-pattern>
|
|
|
<h3 data-uix-pattern-title>Null / NaN · fallback prop</h3>
|
|
|
<div data-uix-pattern-row>
|
|
|
<table data-uix-table>
|
|
|
<thead><tr><th>Markup</th><th>Output</th></tr></thead>
|
|
|
<tbody>
|
|
|
<tr><td><code>value={'{null}'}</code></td><td><strong>"<FormatNumber value={null} />"</strong> (empty)</td></tr>
|
|
|
<tr><td><code>value={'{null}'} fallback="—"</code></td><td><strong><FormatNumber value={null} fallback="—" /></strong></td></tr>
|
|
|
<tr><td><code>value={'{NaN}'} fallback="n/a"</code></td><td><strong><FormatNumber value={NaN} fallback="n/a" /></strong></td></tr>
|
|
|
<tr><td><code>value={'{Infinity}'} fallback="∞"</code></td><td><strong><FormatNumber value={Infinity} fallback="∞" /></strong></td></tr>
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</section>
|
|
|
{/if}
|
|
|
|
|
|
{#if tab === 'api'}
|
|
|
<section data-uix-section>
|
|
|
<h2 data-uix-section-title>API reference</h2>
|
|
|
|
|
|
<div data-uix-table-wrap>
|
|
|
<table data-uix-table>
|
|
|
<thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Notes</th></tr></thead>
|
|
|
<tbody>
|
|
|
<tr><td class="name">value</td><td class="type">number | null</td><td class="default empty">—</td><td>Number to format. <code>null</code>/<code>undefined</code>/<code>NaN</code>/<code>Infinity</code> → renders <code>fallback</code>.</td></tr>
|
|
|
<tr><td class="name">formatStyle</td><td class="type">'decimal' | 'percent' | 'currency' | 'unit'</td><td class="default">'decimal'</td><td>Formatting style. <code>currency</code> requires <code>currency</code> prop; <code>unit</code> requires <code>unit</code>.</td></tr>
|
|
|
<tr><td class="name">currency</td><td class="type">string</td><td class="default empty">— uix.format.currency</td><td>ISO 4217 code. Falls back to the active currency from the runtime.</td></tr>
|
|
|
<tr><td class="name">unit</td><td class="type">string</td><td class="default">'byte'</td><td>Unit identifier (`byte`, `kilometer-per-hour`, `celsius`, …).</td></tr>
|
|
|
<tr><td class="name">currencyDisplay</td><td class="type">'symbol' | 'narrowSymbol' | 'code' | 'name'</td><td class="default">'symbol'</td><td>Currency display flavour.</td></tr>
|
|
|
<tr><td class="name">currencySign</td><td class="type">'standard' | 'accounting'</td><td class="default">'standard'</td><td>`accounting` wraps negatives in parentheses.</td></tr>
|
|
|
<tr><td class="name">unitDisplay</td><td class="type">'long' | 'short' | 'narrow'</td><td class="default">'short'</td><td>Unit label flavour.</td></tr>
|
|
|
<tr><td class="name">notation</td><td class="type">'standard' | 'compact' | 'scientific' | 'engineering'</td><td class="default">'standard'</td><td>`compact` enables "1.2K" / "1 million" displays.</td></tr>
|
|
|
<tr><td class="name">compactDisplay</td><td class="type">'short' | 'long'</td><td class="default">'short'</td><td>"1K" vs "1 thousand".</td></tr>
|
|
|
<tr><td class="name">signDisplay</td><td class="type">'auto' | 'never' | 'always' | 'exceptZero' | 'negative'</td><td class="default">'auto'</td><td>Sign-display policy.</td></tr>
|
|
|
<tr><td class="name">useGrouping</td><td class="type">boolean</td><td class="default">true</td><td>Show grouping separator.</td></tr>
|
|
|
<tr><td class="name">minimumFractionDigits, maximumFractionDigits</td><td class="type">number</td><td class="default empty">—</td><td>Fractional precision bounds.</td></tr>
|
|
|
<tr><td class="name">minimumIntegerDigits</td><td class="type">number</td><td class="default empty">—</td><td>Pads integer part with zeros.</td></tr>
|
|
|
<tr><td class="name">minimumSignificantDigits, maximumSignificantDigits</td><td class="type">number</td><td class="default empty">—</td><td>Significant-digit bounds.</td></tr>
|
|
|
<tr><td class="name">valueAsPercent</td><td class="type">boolean</td><td class="default">false</td><td>When <code>formatStyle="percent"</code> and the caller already scaled to 0-100, set this to skip the × 100 multiplication.</td></tr>
|
|
|
<tr><td class="name">locale</td><td class="type">SupportedLocale</td><td class="default empty">— uix.langs.getLocale()</td><td>Optional locale override.</td></tr>
|
|
|
<tr><td class="name">fallback</td><td class="type">string</td><td class="default">''</td><td>Render when value is null/undefined/NaN/Infinity.</td></tr>
|
|
|
<tr><td class="name">as</td><td class="type">keyof HTMLElementTagNameMap</td><td class="default">'span'</td><td>HTML tag for the rendered element.</td></tr>
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</div>
|
|
|
</section>
|
|
|
{/if}
|
|
|
|
|
|
{#if tab === 'morfo'}
|
|
|
<section data-uix-section>
|
|
|
<h2 data-uix-section-title>
|
|
|
<span data-uix-layer-badge="morfo">morfo</span> · declarative contract
|
|
|
</h2>
|
|
|
<div data-uix-table-wrap>
|
|
|
<table data-uix-table>
|
|
|
<thead><tr><th>Field</th><th>Value</th></tr></thead>
|
|
|
<tbody>
|
|
|
<tr><td class="name">name</td><td>{formatNumberMorfo.name}</td></tr>
|
|
|
<tr><td class="name">kebab</td><td><code>{formatNumberMorfo.kebab}</code></td></tr>
|
|
|
<tr><td class="name">scope</td><td>{formatNumberMorfo.scope.join(', ')}</td></tr>
|
|
|
<tr><td class="name">parts</td><td>{partsList.length}</td></tr>
|
|
|
<tr><td class="name">events</td><td>0</td></tr>
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</div>
|
|
|
</section>
|
|
|
{/if}
|
|
|
|
|
|
{#if tab === 'sema'}
|
|
|
<section data-uix-section>
|
|
|
<h2 data-uix-section-title>
|
|
|
<span data-uix-layer-badge="sema">sema</span> · events
|
|
|
</h2>
|
|
|
<p data-uix-section-desc>
|
|
|
FormatNumber declares <strong>no semantic events</strong>. Number formatting is a
|
|
|
passive transformation, not an evaluative act.
|
|
|
</p>
|
|
|
</section>
|
|
|
{/if}
|
|
|
|
|
|
{#if tab === 'recipe'}
|
|
|
<section data-uix-section>
|
|
|
<h2 data-uix-section-title>Eidos recipe</h2>
|
|
|
<p data-uix-section-desc>
|
|
|
FormatNumber ships <strong>no CSS recipe</strong>. The rendered element is a
|
|
|
plain <code><span></code> (or the <code>as</code> tag) and inherits its
|
|
|
styling from the surrounding context. The <code>[data-format-number]</code>
|
|
|
marker exists only for tooling — l10n audits can target it without affecting
|
|
|
visual output.
|
|
|
</p>
|
|
|
</section>
|
|
|
{/if}
|
|
|
|
|
|
{#if tab === 'a11y'}
|
|
|
<section data-uix-section>
|
|
|
<h2 data-uix-section-title>Accessibility</h2>
|
|
|
<div data-uix-table-wrap>
|
|
|
<table data-uix-table>
|
|
|
<thead><tr><th>Concern</th><th>Contract</th></tr></thead>
|
|
|
<tbody>
|
|
|
<tr>
|
|
|
<td class="name">Reading direction</td>
|
|
|
<td>
|
|
|
Numbers in RTL locales (Arabic, Hebrew) are formatted by
|
|
|
<code>Intl.NumberFormat</code> with the appropriate digit shaping —
|
|
|
FormatNumber doesn't override this.
|
|
|
</td>
|
|
|
</tr>
|
|
|
<tr>
|
|
|
<td class="name">Screen-reader output</td>
|
|
|
<td>
|
|
|
Screen readers read the formatted string verbatim ("one thousand five
|
|
|
hundred dollars" for <code>$1,500</code>). For announcement-style updates,
|
|
|
wrap in <a href="/uix/components/announce"><Announce></a>.
|
|
|
</td>
|
|
|
</tr>
|
|
|
<tr>
|
|
|
<td class="name">Currency code visibility</td>
|
|
|
<td>
|
|
|
Default <code>currencyDisplay="symbol"</code> shows `$`, `€`, `£`. For
|
|
|
unambiguous reading (especially in compact / cross-currency contexts),
|
|
|
consider <code>currencyDisplay="code"</code> ("USD 1,500") or
|
|
|
<code>currencyDisplay="name"</code> ("1,500 US dollars").
|
|
|
</td>
|
|
|
</tr>
|
|
|
<tr>
|
|
|
<td class="name">Falsy values</td>
|
|
|
<td>
|
|
|
<code>value={'{null}'}</code> + empty default fallback renders an empty
|
|
|
element — screen readers skip it. Set <code>fallback="—"</code> or
|
|
|
similar to expose a placeholder explicitly.
|
|
|
</td>
|
|
|
</tr>
|
|
|
</tbody>
|
|
|
</table>
|
|
|
</div>
|
|
|
</section>
|
|
|
{/if}
|
|
|
</div>
|
|
|
|
|
|
<style>
|
|
|
[data-uix-pattern-stack] {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
gap: var(--uix-space-5);
|
|
|
}
|
|
|
[data-uix-pattern-row] {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
gap: var(--uix-space-3);
|
|
|
padding: var(--uix-space-4);
|
|
|
border: 1px solid var(--uix-border);
|
|
|
border-radius: var(--uix-radius-md);
|
|
|
}
|
|
|
h3[data-uix-pattern-title] {
|
|
|
margin: 0 0 var(--uix-space-3);
|
|
|
font-family: var(--uix-font-ui);
|
|
|
font-size: var(--uix-font-size-sm);
|
|
|
font-weight: 600;
|
|
|
color: var(--uix-text-faint);
|
|
|
text-transform: uppercase;
|
|
|
letter-spacing: 0.04em;
|
|
|
}
|
|
|
</style>
|