release: WRNexusJS 0.2.77

This commit is contained in:
2026-07-22 01:26:10 +05:30
parent 569365143b
commit 7ff5b3e8c5
95 changed files with 1077 additions and 177 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ai",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/authz",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/authz — part of the WrNexus framework.",
"license": "MIT",
+11 -11
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/cli",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/cli — part of the WrNexus framework.",
"license": "MIT",
@@ -28,16 +28,16 @@
"wrnexus": "./dist/index.js"
},
"dependencies": {
"@wrnexus/core": "^0.2.76",
"@wrnexus/router": "^0.2.76",
"@wrnexus/csr": "^0.2.76",
"@wrnexus/compiler": "^0.2.76",
"@wrnexus/styles": "^0.2.76",
"@wrnexus/dev-server": "^0.2.76",
"@wrnexus/ui": "^0.2.76",
"@wrnexus/validation": "^0.2.76",
"@wrnexus/i18n": "^0.2.76",
"@wrnexus/db": "^0.2.76"
"@wrnexus/core": "^0.2.77",
"@wrnexus/router": "^0.2.77",
"@wrnexus/csr": "^0.2.77",
"@wrnexus/compiler": "^0.2.77",
"@wrnexus/styles": "^0.2.77",
"@wrnexus/dev-server": "^0.2.77",
"@wrnexus/ui": "^0.2.77",
"@wrnexus/validation": "^0.2.77",
"@wrnexus/i18n": "^0.2.77",
"@wrnexus/db": "^0.2.77"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/compiler",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/compiler — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/core",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/core — part of the WrNexus framework.",
"license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/csr",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/csr — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.2.76"
"@wrnexus/core": "^0.2.77"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/db",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/db — part of the WrNexus framework.",
"license": "MIT",
+14 -14
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/dev-server",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/dev-server — part of the WrNexus framework.",
"license": "MIT",
@@ -25,19 +25,19 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.2.76",
"@wrnexus/dev-toolbar": "^0.2.76",
"@wrnexus/router": "^0.2.76",
"@wrnexus/ssr": "^0.2.76",
"@wrnexus/csr": "^0.2.76",
"@wrnexus/compiler": "^0.2.76",
"@wrnexus/styles": "^0.2.76",
"@wrnexus/ui": "^0.2.76",
"@wrnexus/validation": "^0.2.76",
"@wrnexus/i18n": "^0.2.76",
"@wrnexus/db": "^0.2.76",
"@wrnexus/pubsub": "^0.2.76",
"@wrnexus/uploader": "^0.2.76"
"@wrnexus/core": "^0.2.77",
"@wrnexus/dev-toolbar": "^0.2.77",
"@wrnexus/router": "^0.2.77",
"@wrnexus/ssr": "^0.2.77",
"@wrnexus/csr": "^0.2.77",
"@wrnexus/compiler": "^0.2.77",
"@wrnexus/styles": "^0.2.77",
"@wrnexus/ui": "^0.2.77",
"@wrnexus/validation": "^0.2.77",
"@wrnexus/i18n": "^0.2.77",
"@wrnexus/db": "^0.2.77",
"@wrnexus/pubsub": "^0.2.77",
"@wrnexus/uploader": "^0.2.77"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/dev-toolbar",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/dev-toolbar — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/encryption",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/encryption — part of the WrNexus framework.",
"license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/helpers",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.2.76"
"@wrnexus/core": "^0.2.77"
},
"files": [
"dist"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/i18n",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/i18n — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.2.76"
"@wrnexus/core": "^0.2.77"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/jwt",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/jwt — part of the WrNexus framework.",
"license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/mobile",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/mobile — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/native": "^0.2.76"
"@wrnexus/native": "^0.2.77"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/native",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/native — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/oauth",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/oauth — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/pubsub",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/pubsub — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/queue",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/queue — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/reactive",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/reactive — part of the WrNexus framework.",
"license": "MIT",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/router",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/router — part of the WrNexus framework.",
"license": "MIT",
@@ -21,8 +21,8 @@
}
},
"dependencies": {
"@wrnexus/compiler": "^0.2.76",
"@wrnexus/core": "^0.2.76"
"@wrnexus/compiler": "^0.2.77",
"@wrnexus/core": "^0.2.77"
},
"files": [
"dist"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ssr",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/ssr — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.2.76"
"@wrnexus/core": "^0.2.77"
},
"files": [
"dist"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/styles",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/styles — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/uploader": "^0.2.76"
"@wrnexus/uploader": "^0.2.77"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/test",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/test — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/tracking",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/tracking — part of the WrNexus framework.",
"license": "MIT",
@@ -9,7 +9,43 @@ component AnalyticsDashboardPreview {
alt = ""
class = ""
}
view {
<article class="wire-card wire-catalog-card {class}">{#if image}<img src="{image}" alt="{alt}" class="wire-catalog-card__image" />{:else}<div role="img" aria-label="Communication performance chart trending upward over seven days" class="grid min-h-64 gap-4 rounded-xl border border-slate-200 bg-slate-50 p-5 dark:border-slate-800 dark:bg-slate-950/60"><div class="flex items-center justify-between"><span class="text-sm font-semibold">Delivery trend</span><span class="inline-flex items-center gap-1 text-xs font-bold text-emerald-500"><span class="icon-[lucide--trending-up] size-4" aria-hidden="true"></span>18.4%</span></div><svg viewBox="0 0 600 190" role="presentation" class="h-auto w-full overflow-visible"><defs><linearGradient id="wire-analytics-fill" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="currentColor" stop-opacity="0.28"></stop><stop offset="100%" stop-color="currentColor" stop-opacity="0"></stop></linearGradient></defs><g stroke="currentColor" stroke-opacity="0.12"><path d="M0 30H600M0 80H600M0 130H600M0 180H600"></path></g><path d="M0 157 C55 150 70 118 124 126 S205 152 255 103 S342 91 392 98 S470 67 515 74 S566 38 600 30 L600 190 L0 190 Z" fill="url(#wire-analytics-fill)" class="text-violet-500"></path><path d="M0 157 C55 150 70 118 124 126 S205 152 255 103 S342 91 392 98 S470 67 515 74 S566 38 600 30" fill="none" stroke="currentColor" stroke-width="5" stroke-linecap="round" class="text-violet-500"></path><g fill="currentColor" class="text-violet-500"><circle cx="124" cy="126" r="5"></circle><circle cx="255" cy="103" r="5"></circle><circle cx="392" cy="98" r="5"></circle><circle cx="515" cy="74" r="5"></circle><circle cx="600" cy="30" r="6"></circle></g></svg><div class="flex justify-between text-[0.6875rem] text-slate-500"><span>Mon</span><span>Tue</span><span>Wed</span><span>Thu</span><span>Fri</span><span>Sat</span><span>Sun</span></div></div>{/if}{#if eyebrow}<span class="wire-eyebrow">{eyebrow}</span>{/if}{#if title}<h3>{title}</h3>{/if}{#if description}<p>{description}</p>{/if}<slot />{#if href}<a href="{href}" class="wire-btn wire-btn--ghost">{actionLabel}</a>{/if}</article>
<section class="px-4 sm:px-6 lg:px-8 {class}">
<div class="mx-auto grid w-full max-w-7xl gap-8 overflow-hidden rounded-3xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-5 shadow-[var(--wire-shadow-md,0_12px_30px_rgb(0_0_0/0.08))] sm:p-7 lg:grid-cols-[1.25fr_0.75fr] lg:items-center lg:p-8">
<div>
{#if image}
<img src="{image}" alt="{alt}" class="aspect-[16/9] w-full rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] object-cover" />
{:else}
<div class="rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface-muted,#f8fafc)] p-4 sm:p-5" role="img" aria-label="Delivery trend rising over seven days">
<div class="flex items-center justify-between gap-4 text-sm">
<strong class="text-[var(--wire-color-text,#0f172a)]">Delivery trend</strong>
<span class="font-bold text-[var(--wire-color-success,#059669)]">↗ 18.4%</span>
</div>
<svg class="mt-4 h-auto w-full text-[var(--wire-color-primary,#059669)]" viewBox="0 0 700 250" aria-hidden="true">
<defs>
<linearGradient id="wire-analytics-area" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="currentColor" stop-opacity=".24"></stop>
<stop offset="100%" stop-color="currentColor" stop-opacity="0"></stop>
</linearGradient>
</defs>
<g fill="none" stroke="var(--wire-color-border,#e2e8f0)"><path d="M20 50H680M20 115H680M20 180H680M20 230H680"></path></g>
<path fill="url(#wire-analytics-area)" d="M20 210 C100 195 120 150 190 165 S310 195 370 120 S475 130 525 100 S610 90 680 32 L680 230 L20 230Z"></path>
<path fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" d="M20 210 C100 195 120 150 190 165 S310 195 370 120 S475 130 525 100 S610 90 680 32"></path>
</svg>
<div class="mt-2 flex justify-between text-[0.7rem] text-[var(--wire-color-text-muted,#64748b)]"><span>Mon</span><span>Tue</span><span>Wed</span><span>Thu</span><span>Fri</span><span>Sat</span><span>Sun</span></div>
</div>
{/if}
</div>
<div>
{#if eyebrow}<p class="m-0 text-xs font-bold uppercase tracking-[0.16em] text-[var(--wire-color-primary,#059669)]">{eyebrow}</p>{/if}
{#if title}<h2 class="mt-4 text-3xl font-semibold tracking-[-0.035em] text-[var(--wire-color-text,#0f172a)]">{title}</h2>{/if}
{#if description}<p class="mt-4 leading-7 text-[var(--wire-color-text-muted,#64748b)]">{description}</p>{/if}
<div class="mt-5"><slot /></div>
{#if href}<a href="{href}" class="mt-6 inline-flex items-center gap-2 font-semibold text-[var(--wire-color-primary,#059669)] no-underline">{actionLabel}<span aria-hidden="true">→</span></a>{/if}
</div>
</div>
</section>
}
}
+21 -2
View File
@@ -3,8 +3,27 @@ component ChannelCard {
title = ""
description = ""
href = ""
icon = "icon-[lucide--radio-tower]"
icon = ""
class = ""
}
view { <article class="wire-card wire-catalog-card wire-catalog-card--channel {class}"><span class="wire-catalog-card__icon"><span class="{icon} size-5" aria-hidden="true"></span></span>{#if title}<h3>{title}</h3>{/if}{#if description}<p>{description}</p>{/if}<slot />{#if href}<a href="{href}" class="wire-catalog-card__link"><span class="wire-visually-hidden">Open {title}</span></a>{/if}</article> }
view {
<article class="group flex h-full min-h-72 flex-col rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-6 shadow-[var(--wire-shadow-sm,0_1px_2px_rgb(0_0_0/0.05))] transition duration-200 hover:-translate-y-1 hover:border-[var(--wire-color-primary,#059669)] hover:shadow-[var(--wire-shadow-md,0_12px_30px_rgb(0_0_0/0.10))] {class}">
<div class="flex min-h-12 items-start justify-between gap-4">
{#if icon}
<span class="inline-grid h-12 w-12 shrink-0 place-items-center rounded-xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-primary-soft,#ecfdf5)] text-xl text-[var(--wire-color-primary,#059669)] {icon}" aria-hidden="true"></span>
{/if}
<div class="flex min-w-0 justify-end"><slot /></div>
</div>
{#if title}<h3 class="mt-5 text-xl font-semibold tracking-[-0.02em] text-[var(--wire-color-text,#0f172a)]">{title}</h3>{/if}
{#if description}<p class="mt-3 flex-1 leading-7 text-[var(--wire-color-text-muted,#64748b)]">{description}</p>{/if}
{#if href}
<a href="{href}" class="mt-6 inline-flex items-center justify-between gap-3 border-t border-[var(--wire-color-border,#e2e8f0)] pt-5 font-semibold text-[var(--wire-color-primary,#059669)] no-underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-primary,#059669)]" aria-label="Explore {title}">
<span>Explore {title}</span><span class="transition-transform group-hover:translate-x-0.5" aria-hidden="true">→</span>
</a>
{/if}
</article>
}
}
+32 -6
View File
@@ -1,11 +1,37 @@
component ChannelFlow {
props {
title = ""
value = ""
description = ""
summary = ""
loading = false
class = ""
}
view { <figure aria-label="{summary || title}" class="wire-card wire-catalog-visualization {class}"><figcaption><strong data-show="title">{title}</strong><span data-show="value" class="wire-metric__value">{value}</span><span data-show="description" class="wire-muted">{description}</span></figcaption><div data-show="loading" class="wire-skeleton wire-catalog-visualization__skeleton"></div><div data-show="!loading" class="wire-catalog-visualization__content"><slot /></div><p data-show="summary" class="wire-visually-hidden">{summary}</p></figure> }
view {
<div class="grid grid-cols-1 items-center gap-3 lg:grid-cols-[1fr_auto_1fr_auto_1.2fr_auto_1fr] {class}" role="img" aria-label="Customer event flows through profile and consent checks to communication channels, then delivery analytics and webhooks">
<div class="rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-4">
<span class="icon-[lucide--webhook] text-xl text-[var(--wire-color-primary,#059669)]" aria-hidden="true"></span>
<strong class="mt-3 block text-sm text-[var(--wire-color-text,#0f172a)]">Customer event</strong>
<small class="mt-1 block text-[var(--wire-color-text-muted,#64748b)]">order.shipped</small>
</div>
<span class="hidden text-center text-xl text-[var(--wire-color-primary,#059669)] lg:block" aria-hidden="true">→</span>
<div class="rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-4">
<span class="icon-[lucide--shield-check] text-xl text-[var(--wire-color-primary,#059669)]" aria-hidden="true"></span>
<strong class="mt-3 block text-sm text-[var(--wire-color-text,#0f172a)]">Profile + consent</strong>
<small class="mt-1 block text-[var(--wire-color-text-muted,#64748b)]">Eligibility checked</small>
</div>
<span class="hidden text-center text-xl text-[var(--wire-color-primary,#059669)] lg:block" aria-hidden="true">→</span>
<div class="grid grid-cols-2 gap-2 rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-3">
<span class="rounded-xl bg-[var(--wire-color-primary-soft,#ecfdf5)] px-3 py-2.5 text-center text-xs font-bold text-[var(--wire-color-primary,#059669)]">WhatsApp</span>
<span class="rounded-xl bg-[var(--wire-color-primary-soft,#ecfdf5)] px-3 py-2.5 text-center text-xs font-bold text-[var(--wire-color-primary,#059669)]">SMS</span>
<span class="rounded-xl bg-[var(--wire-color-primary-soft,#ecfdf5)] px-3 py-2.5 text-center text-xs font-bold text-[var(--wire-color-primary,#059669)]">Email</span>
<span class="rounded-xl bg-[var(--wire-color-primary-soft,#ecfdf5)] px-3 py-2.5 text-center text-xs font-bold text-[var(--wire-color-primary,#059669)]">Voice</span>
</div>
<span class="hidden text-center text-xl text-[var(--wire-color-primary,#059669)] lg:block" aria-hidden="true">→</span>
<div class="rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-4">
<span class="icon-[lucide--chart-no-axes-combined] text-xl text-[var(--wire-color-primary,#059669)]" aria-hidden="true"></span>
<strong class="mt-3 block text-sm text-[var(--wire-color-text,#0f172a)]">Delivery + analytics</strong>
<small class="mt-1 block text-[var(--wire-color-text-muted,#64748b)]">Webhook emitted</small>
</div>
</div>
}
}
+5 -3
View File
@@ -1,9 +1,11 @@
component Cluster {
props {
gap = "4"
className = ""
class = ""
}
view {
<div class="flex flex-wrap items-center gap-{gap} {className}"><slot /></div>
<div class="flex flex-wrap items-center gap-3 {class}">
<slot />
</div>
}
}
+18 -4
View File
@@ -1,12 +1,26 @@
component CodeBlock {
props {
class = ""
language = "text"
filename = ""
title = ""
code = ""
copyable = true
class = ""
}
state copied = false
view {
<div class="min-w-0 overflow-hidden rounded-2xl border border-slate-800 bg-slate-950 text-slate-100 shadow-2xl shadow-slate-950/20 {class}"><div class="flex min-h-12 items-center justify-between gap-4 border-b border-slate-800 px-4 text-xs text-slate-400"><span class="inline-flex min-w-0 items-center gap-2 truncate"><span class="icon-[lucide--terminal] size-4 shrink-0" aria-hidden="true"></span>{filename || language}</span><button type="button" @click="navigator.clipboard.writeText(code); copied = true" class="inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-slate-700 px-2.5 py-1.5 font-semibold text-slate-300 transition hover:border-slate-600 hover:bg-slate-800 hover:text-white"><span class="{copied ? 'icon-[lucide--check]' : 'icon-[lucide--copy]'} size-3.5" aria-hidden="true"></span>{copied ? 'Copied' : 'Copy'}</button></div><pre class="m-0 max-w-full overflow-x-auto whitespace-pre-wrap break-words p-5 font-mono text-[0.8125rem] leading-6 sm:whitespace-pre"><code>{code}</code></pre></div>
<section class="overflow-hidden bg-[var(--wire-color-code-background,#020617)] text-[var(--wire-color-code-text,#e2e8f0)] {class}">
<header class="flex items-center justify-between gap-4 border-b border-[var(--wire-color-code-border,#1e293b)] px-4 py-3 text-xs text-[var(--wire-color-code-muted,#94a3b8)] sm:px-5">
<span class="inline-flex items-center gap-2 font-medium">
<span class="icon-[lucide--terminal]" aria-hidden="true"></span>
{#if title}{title}{:else}{language}{/if}
</span>
{#if copyable}
<button type="button" data-copy-code="{code}" class="inline-flex items-center gap-2 rounded-lg border border-[var(--wire-color-code-border,#334155)] px-3 py-1.5 font-semibold text-[var(--wire-color-code-text,#e2e8f0)] transition hover:bg-[var(--wire-color-code-surface,#0f172a)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-primary,#059669)]">
<span class="icon-[lucide--copy]" aria-hidden="true"></span>Copy
</button>
{/if}
</header>
<pre class="m-0 max-w-full overflow-x-auto p-5 text-sm leading-7"><code>{code}</code></pre>
</section>
}
}
+6 -8
View File
@@ -1,13 +1,11 @@
component CodeTabs {
props {
eyebrow = ""
title = ""
description = ""
href = ""
actionLabel = "Learn more"
image = ""
alt = ""
class = ""
}
view { <article class="wire-card wire-catalog-card {class}">{#if image}<img src="{image}" alt="{alt}" class="wire-catalog-card__image" />{/if}{#if eyebrow}<span class="wire-eyebrow">{eyebrow}</span>{/if}{#if title}<h3>{title}</h3>{/if}{#if description}<p>{description}</p>{/if}<slot />{#if href}<a href="{href}" class="wire-btn wire-btn--ghost">{actionLabel}</a>{/if}</article> }
view {
<div class="overflow-hidden rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] shadow-[var(--wire-shadow-sm,0_1px_2px_rgb(0_0_0/0.05))] {class}">
<slot />
</div>
}
}
+20 -1
View File
@@ -9,5 +9,24 @@ component FeatureTabs {
alt = ""
class = ""
}
view { <article class="wire-card wire-catalog-card {class}">{#if image}<img src="{image}" alt="{alt}" class="wire-catalog-card__image" />{/if}{#if eyebrow}<span class="wire-eyebrow">{eyebrow}</span>{/if}{#if title}<h3>{title}</h3>{/if}{#if description}<p>{description}</p>{/if}<slot />{#if href}<a href="{href}" class="wire-btn wire-btn--ghost">{actionLabel}</a>{/if}</article> }
view {
<article class="group flex h-full min-h-72 flex-col overflow-hidden rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] shadow-[var(--wire-shadow-sm,0_1px_2px_rgb(0_0_0/0.05))] transition duration-200 hover:-translate-y-1 hover:border-[var(--wire-color-primary,#059669)] hover:shadow-[var(--wire-shadow-md,0_12px_30px_rgb(0_0_0/0.10))] {class}">
{#if image}
<img src="{image}" alt="{alt}" class="aspect-[16/9] w-full border-b border-[var(--wire-color-border,#e2e8f0)] object-cover" />
{/if}
<div class="flex flex-1 flex-col p-6">
{#if eyebrow}<p class="m-0 text-xs font-bold uppercase tracking-[0.14em] text-[var(--wire-color-primary,#059669)]">{eyebrow}</p>{/if}
{#if title}<h3 class="mt-4 text-xl font-semibold leading-snug tracking-[-0.02em] text-[var(--wire-color-text,#0f172a)]">{title}</h3>{/if}
{#if description}<p class="mt-3 flex-1 leading-7 text-[var(--wire-color-text-muted,#64748b)]">{description}</p>{/if}
<div class="mt-5"><slot /></div>
{#if href}
<a href="{href}" class="mt-6 inline-flex items-center gap-2 font-semibold text-[var(--wire-color-primary,#059669)] no-underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-primary,#059669)]">
<span>{actionLabel}</span><span class="transition-transform group-hover:translate-x-0.5" aria-hidden="true">→</span>
</a>
{/if}
</div>
</article>
}
}
+26 -2
View File
@@ -1,11 +1,35 @@
component FinalCTA {
props {
label = "Action"
label = "Get started"
href = ""
type = "button"
variant = "primary"
disabled = false
class = ""
}
view { <span class="wire-catalog-action {class}">{#if href}<a href="{href}" class="wire-btn wire-btn--{variant}">{label}<slot /></a>{:else}<button type="{type}" disabled="{disabled}" class="wire-btn wire-btn--{variant}">{label}<slot /></button>{/if}</span> }
view {
<span class="contents {class}">
{#if href}
<a
href="{href}"
class=' group inline-flex min-h-11 items-center justify-center gap-2 rounded-xl px-5 py-2.5 text-sm font-semibold no-underline transition duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-primary,#059669)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--wire-color-background,#ffffff)] {variant === "primary" ? "bg-[var(--wire-color-primary,#059669)] text-[var(--wire-color-primary-contrast,#ffffff)] hover:bg-[var(--wire-color-primary-hover,#047857)]" : "border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] text-[var(--wire-color-text,#0f172a)] hover:border-[var(--wire-color-primary,#059669)] hover:text-[var(--wire-color-primary,#059669)]"} '
aria-disabled="{disabled}"
>
<span>{label}</span>
<span class="transition-transform duration-200 group-hover:translate-x-0.5" aria-hidden="true">→</span>
<slot />
</a>
{:else}
<button
type="{type}"
disabled="{disabled}"
class=' group inline-flex min-h-11 items-center justify-center gap-2 rounded-xl px-5 py-2.5 text-sm font-semibold transition duration-200 disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-primary,#059669)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--wire-color-background,#ffffff)] {variant === "primary" ? "bg-[var(--wire-color-primary,#059669)] text-[var(--wire-color-primary-contrast,#ffffff)] hover:bg-[var(--wire-color-primary-hover,#047857)]" : "border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] text-[var(--wire-color-text,#0f172a)] hover:border-[var(--wire-color-primary,#059669)] hover:text-[var(--wire-color-primary,#059669)]"} '
>
<span>{label}</span>
<slot />
</button>
{/if}
</span>
}
}
@@ -6,5 +6,30 @@ component MarketingSectionHeader {
align = "start"
class = ""
}
view { <section class="wire-catalog-section wire-text--{align} {class}"><header data-show="eyebrow || title || description"><span data-show="eyebrow" class="wire-eyebrow">{eyebrow}</span><h2 data-show="title">{title}</h2><p data-show="description" class="wire-muted">{description}</p></header><slot /></section> }
view {
<section class="px-4 py-16 sm:px-6 sm:py-20 lg:px-8 {class}">
<div class="mx-auto w-full max-w-7xl">
<header
class="max-w-3xl"
class:mx-auto='{align === "center"}'
class:text-center='{align === "center"}'
>
{#if eyebrow}
<p class="mb-3 text-xs font-bold uppercase tracking-[0.16em] text-[var(--wire-color-primary,#059669)] sm:text-sm">{eyebrow}</p>
{/if}
{#if title}
<h2 class="m-0 text-3xl font-semibold tracking-[-0.035em] text-[var(--wire-color-text,#0f172a)] sm:text-4xl">{title}</h2>
{/if}
{#if description}
<p class="mt-5 text-base leading-8 text-[var(--wire-color-text-muted,#64748b)] sm:text-lg">{description}</p>
{/if}
</header>
<div class="mt-8">
<slot />
</div>
</div>
</section>
}
}
+23 -2
View File
@@ -1,8 +1,29 @@
component MetricGrid {
props {
label = "Key metrics"
label = "Platform metrics"
metrics = []
class = ""
}
view { <section aria-label="{label}" class="wire-metric-grid {class}">{#each metrics as metric}<article class="wire-metric"><p class="wire-metric__value">{metric.value}</p><p class="wire-metric__label">{metric.label}</p><p data-show="metric.description" class="wire-metric__description">{metric.description}</p></article>{/each}</section> }
view {
<section class="px-4 sm:px-6 lg:px-8 {class}" aria-label="{label}">
<div class="mx-auto grid w-full max-w-7xl grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
{#each metrics as metric}
<article class="flex min-h-40 flex-col justify-center rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-6 shadow-[var(--wire-shadow-sm,0_1px_2px_rgb(0_0_0/0.05))]">
<strong class="text-3xl font-semibold leading-none tracking-[-0.04em] text-[var(--wire-color-text,#0f172a)] sm:text-4xl">
{metric.value}
</strong>
<span class="mt-4 font-semibold text-[var(--wire-color-text,#0f172a)]">{metric.label}</span>
{#if metric.description}
<p class="mt-2 text-sm leading-6 text-[var(--wire-color-text-muted,#64748b)]">{metric.description}</p>
{/if}
</article>
{:empty}
<p class="col-span-full rounded-2xl border border-dashed border-[var(--wire-color-border,#e2e8f0)] p-8 text-center text-[var(--wire-color-text-muted,#64748b)]">
No metrics available.
</p>
{/each}
</div>
</section>
}
}
@@ -7,5 +7,29 @@ component ProductArchitectureDiagram {
loading = false
class = ""
}
view { <figure aria-label="{summary || title}" class="wire-card wire-catalog-visualization {class}"><figcaption><strong data-show="title">{title}</strong><span data-show="value" class="wire-metric__value">{value}</span><span data-show="description" class="wire-muted">{description}</span></figcaption><div data-show="loading" class="wire-skeleton wire-catalog-visualization__skeleton"></div><div data-show="!loading" class="wire-catalog-visualization__content"><slot /></div><p data-show="summary" class="wire-visually-hidden">{summary}</p></figure> }
view {
<section class="overflow-hidden rounded-3xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] shadow-[var(--wire-shadow-md,0_12px_30px_rgb(0_0_0/0.08))] {class}" aria-label="{title}">
<header class="flex flex-col gap-4 border-b border-[var(--wire-color-border,#e2e8f0)] p-6 sm:flex-row sm:items-start sm:justify-between lg:p-8">
<div>
{#if title}<p class="m-0 font-semibold text-[var(--wire-color-text,#0f172a)]">{title}</p>{/if}
{#if value}<strong class="mt-3 block text-3xl font-semibold tracking-[-0.04em] text-[var(--wire-color-text,#0f172a)] sm:text-4xl">{value}</strong>{/if}
{#if description}<p class="mt-3 max-w-2xl leading-7 text-[var(--wire-color-text-muted,#64748b)]">{description}</p>{/if}
</div>
{#if loading}
<span class="inline-flex w-max items-center gap-2 rounded-full bg-[var(--wire-color-surface-muted,#f8fafc)] px-3 py-1.5 text-xs font-semibold text-[var(--wire-color-text-muted,#64748b)]">
<span class="h-2 w-2 animate-pulse rounded-full bg-[var(--wire-color-primary,#059669)]"></span>Loading
</span>
{/if}
</header>
<div class="bg-[var(--wire-color-surface-muted,#f8fafc)] p-4 sm:p-6 lg:p-8 empty:hidden">
<slot />
</div>
{#if summary}
<p class="m-0 border-t border-[var(--wire-color-border,#e2e8f0)] px-6 py-5 text-sm leading-6 text-[var(--wire-color-text-muted,#64748b)] lg:px-8">{summary}</p>
{/if}
</section>
}
}
+19 -4
View File
@@ -1,12 +1,27 @@
component ProductCard {
props {
eyebrow = "Product"
title = "Product name"
eyebrow = ""
title = ""
description = ""
href = "#"
href = ""
actionLabel = "Learn more"
status = ""
class = ""
}
view { <article class="wire-product-card {class}"><div class="wire-product-card__meta"><span class="wire-eyebrow">{eyebrow}</span><span data-show="status" class="wire-badge">{status}</span></div><h3>{title}</h3><p>{description}</p><a href="{href}" class="wire-product-card__link">{actionLabel}<span aria-hidden="true"> →</span></a></article> }
view {
<article class="group flex h-full min-h-72 flex-col rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-6 shadow-[var(--wire-shadow-sm,0_1px_2px_rgb(0_0_0/0.05))] transition duration-200 hover:-translate-y-1 hover:border-[var(--wire-color-primary,#059669)] hover:shadow-[var(--wire-shadow-md,0_12px_30px_rgb(0_0_0/0.10))] {class}">
<div class="flex min-h-7 items-start justify-between gap-4">
{#if eyebrow}<span class="text-xs font-bold uppercase tracking-[0.14em] text-[var(--wire-color-primary,#059669)]">{eyebrow}</span>{/if}
{#if status}<span class="shrink-0 rounded-full bg-[var(--wire-color-surface-muted,#f8fafc)] px-2.5 py-1 text-[0.7rem] font-bold text-[var(--wire-color-text-muted,#64748b)]">{status}</span>{/if}
</div>
{#if title}<h3 class="mt-5 text-xl font-semibold tracking-[-0.02em] text-[var(--wire-color-text,#0f172a)]">{title}</h3>{/if}
{#if description}<p class="mt-3 flex-1 leading-7 text-[var(--wire-color-text-muted,#64748b)]">{description}</p>{/if}
{#if href}
<a href="{href}" class="mt-6 inline-flex items-center gap-2 border-t border-[var(--wire-color-border,#e2e8f0)] pt-5 font-semibold text-[var(--wire-color-primary,#059669)] no-underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-primary,#059669)]">
<span>{actionLabel}</span><span class="transition-transform group-hover:translate-x-0.5" aria-hidden="true">→</span>
</a>
{/if}
</article>
}
}
+19 -1
View File
@@ -6,5 +6,23 @@ component ProductGrid {
emptyText = "No items available."
class = ""
}
view { <section class="wire-catalog-collection {class}"><header data-show="title || description"><h2 data-show="title">{title}</h2><p data-show="description">{description}</p></header><div data-show="!empty" role="list" class="wire-catalog-collection__items"><slot /></div><p data-show="empty" role="status" class="wire-muted">{emptyText}</p></section> }
view {
<section class="px-4 sm:px-6 lg:px-8 {class}">
<div class="mx-auto w-full max-w-7xl">
{#if title}<h2 class="m-0 text-3xl font-semibold tracking-[-0.035em] text-[var(--wire-color-text,#0f172a)]">{title}</h2>{/if}
{#if description}<p class="mt-4 max-w-3xl leading-7 text-[var(--wire-color-text-muted,#64748b)]">{description}</p>{/if}
{#if empty}
<div class="mt-8 rounded-2xl border border-dashed border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface-muted,#f8fafc)] p-10 text-center text-[var(--wire-color-text-muted,#64748b)]">
{emptyText}
</div>
{:else}
<div class="mt-8 grid grid-cols-1 items-stretch gap-5 md:grid-cols-2 xl:grid-cols-3 [&>*]:min-w-0 [&>*]:h-full">
<slot />
</div>
{/if}
</div>
</section>
}
}
+46 -1
View File
@@ -6,5 +6,50 @@ component ProductHero {
align = "start"
class = ""
}
view { <section class="wire-catalog-section wire-text--{align} {class}"><header data-show="eyebrow || title || description"><span data-show="eyebrow" class="wire-eyebrow">{eyebrow}</span><h2 data-show="title">{title}</h2><p data-show="description" class="wire-muted">{description}</p></header><slot /></section> }
view {
<section
class="
relative isolate overflow-hidden border-b border-[var(--wire-color-border,#e2e8f0)]
bg-[var(--wire-color-background,#ffffff)] px-4 py-16 sm:px-6 sm:py-20 lg:px-8 lg:py-24
{class}
"
>
<div
class="pointer-events-none absolute inset-0 -z-10 opacity-80"
style="background: radial-gradient(circle at 16% 0%, color-mix(in srgb, var(--wire-color-primary, #059669) 16%, transparent), transparent 36%);"
aria-hidden="true"
></div>
<div class="mx-auto w-full max-w-7xl">
<div
class="max-w-4xl"
class:mx-auto='{align === "center"}'
class:text-center='{align === "center"}'
>
{#if eyebrow}
<p class="mb-4 text-xs font-bold uppercase tracking-[0.18em] text-[var(--wire-color-primary,#059669)] sm:text-sm">
{eyebrow}
</p>
{/if}
{#if title}
<h1 class="m-0 max-w-[18ch] text-4xl font-semibold leading-[1.05] tracking-[-0.045em] text-[var(--wire-color-text,#0f172a)] sm:text-5xl lg:text-6xl" class:mx-auto='{align === "center"}'>
{title}
</h1>
{/if}
{#if description}
<p class="mt-6 max-w-3xl text-base leading-8 text-[var(--wire-color-text-muted,#64748b)] sm:text-lg" class:mx-auto='{align === "center"}'>
{description}
</p>
{/if}
</div>
<div class="mt-8 space-y-8">
<slot />
</div>
</div>
</section>
}
}
+15 -3
View File
@@ -1,6 +1,18 @@
component ProductPageShell {
props {
class = ""
props { class = "" }
view {
<main
class="
min-h-screen w-full overflow-x-clip
bg-[var(--wire-color-background,#ffffff)]
font-[var(--wire-font-sans,ui-sans-serif,system-ui,sans-serif)]
text-[var(--wire-color-text,#0f172a)]
antialiased
{class}
"
>
<slot />
</main>
}
view { <div class="wire-page-shell wire-page-shell--product {class}"><slot /></div> }
}
+11 -3
View File
@@ -1,8 +1,16 @@
component ProductStatusBadge {
props {
label = "ProductStatus"
variant = "default"
label = "Available"
status = ""
class = ""
}
view { <span class="wire-badge wire-badge--{variant} wire-catalog-badge wire-catalog-badge--productstatusbadge {class}">{label}<slot /></span> }
view {
<span
class=' inline-flex w-max items-center gap-1.5 rounded-full border px-2.5 py-1 text-[0.7rem] font-bold leading-none {status === "warning" ? "border-[var(--wire-color-warning,#d97706)] bg-[var(--wire-color-warning-soft,#fffbeb)] text-[var(--wire-color-warning,#d97706)]" : status === "muted" ? "border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface-muted,#f8fafc)] text-[var(--wire-color-text-muted,#64748b)]" : "border-[var(--wire-color-primary,#059669)] bg-[var(--wire-color-primary-soft,#ecfdf5)] text-[var(--wire-color-primary,#059669)]"} {class} '
>
<span class="h-1.5 w-1.5 rounded-full bg-current" aria-hidden="true"></span>
{label}
</span>
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ui",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/ui — part of the WrNexus framework.",
"license": "MIT",
@@ -25,7 +25,7 @@
"./ui.css": "./ui.css"
},
"dependencies": {
"@wrnexus/core": "^0.2.76"
"@wrnexus/core": "^0.2.77"
},
"files": [
"dist",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/uploader",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/uploader — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.2.76"
"@wrnexus/core": "^0.2.77"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/validation",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"description": "@wrnexus/validation — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "wrnexus",
"displayName": "WRNexus Language Support",
"description": "Complete language support for WRNexus .wrn files, including highlighting, formatting, diagnostics, snippets, lifecycle hooks, state watchers, component functions, completions, and definition navigation.",
"version": "0.2.14",
"version": "0.2.15",
"publisher": "wrnexus",
"private": true,
"license": "SEE LICENSE IN LICENSE",
+66 -1
View File
@@ -173,6 +173,71 @@ class Lexer {
v += src[this.pos++];
return v.trim();
}
readPropInitializer() {
const { src } = this;
let value = "";
let square = 0;
let brace = 0;
let paren = 0;
let quote = null;
const beginsPropDeclaration = (position) => {
let cursor = position;
while (cursor < src.length && (src[cursor] === " " || src[cursor] === "\t"))
cursor++;
if (!isIdentStart(src[cursor] ?? ""))
return false;
cursor++;
while (cursor < src.length && isIdentPart(src[cursor]))
cursor++;
while (cursor < src.length && (src[cursor] === " " || src[cursor] === "\t"))
cursor++;
return src[cursor] === "=" || src[cursor] === ":";
};
while (this.pos < src.length) {
const c = src[this.pos];
if (quote) {
value += c;
this.pos++;
if (c === "\\" && this.pos < src.length)
value += src[this.pos++];
else if (c === quote)
quote = null;
continue;
}
if (c === '"' || c === "'" || c === "`") {
quote = c;
value += c;
this.pos++;
continue;
}
if (c === "[")
square++;
else if (c === "]" && square > 0)
square--;
else if (c === "{")
brace++;
else if (c === "}" && brace > 0)
brace--;
else if (c === "(")
paren++;
else if (c === ")" && paren > 0)
paren--;
const topLevel = square === 0 && brace === 0 && paren === 0;
if (topLevel) {
if (c === `
` || c === "\r" || c === "}")
break;
if ((c === " " || c === "\t") && beginsPropDeclaration(this.pos))
break;
}
value += c;
this.pos++;
}
const result = value.trim();
if (!result)
throw new LexError(`Expected a prop initializer at offset ${this.pos}`);
return result;
}
readTypeAnnotation() {
const { src } = this;
let value = "";
@@ -471,7 +536,7 @@ function parse(source) {
expect("eq");
hasDefault = true;
}
const defaultValue = hasDefault ? lx.readToLineEnd() : "undefined";
const defaultValue = hasDefault ? lx.readPropInitializer() : "undefined";
props.push({ name: pName, valueType, required: !hasDefault, default: defaultValue });
}
expect("rbrace");
+93
View File
@@ -17,6 +17,91 @@ const VOID_ELEMENTS = new Set([
"wbr",
]);
function splitPropDeclarations(value) {
const declarations = [];
let start = 0;
let index = 0;
let quote = null;
let escaped = false;
let square = 0;
let brace = 0;
let paren = 0;
const isIdentifierStart = (character) => /[A-Za-z_]/.test(character || "");
const isIdentifierPart = (character) => /[A-Za-z0-9_]/.test(character || "");
const beginsDeclaration = (position) => {
let cursor = position;
while (cursor < value.length && /[ \t]/.test(value[cursor])) cursor += 1;
if (!isIdentifierStart(value[cursor])) return false;
cursor += 1;
while (cursor < value.length && isIdentifierPart(value[cursor])) cursor += 1;
while (cursor < value.length && /[ \t]/.test(value[cursor])) cursor += 1;
return value[cursor] === "=" || value[cursor] === ":";
};
while (index < value.length) {
const character = value[index];
if (quote !== null) {
if (escaped) escaped = false;
else if (character === "\\") escaped = true;
else if (character === quote) quote = null;
index += 1;
continue;
}
if (character === '"' || character === "'" || character === "`") {
quote = character;
index += 1;
continue;
}
if (character === "[") square += 1;
else if (character === "]" && square > 0) square -= 1;
else if (character === "{") brace += 1;
else if (character === "}" && brace > 0) brace -= 1;
else if (character === "(") paren += 1;
else if (character === ")" && paren > 0) paren -= 1;
if (
square === 0 &&
brace === 0 &&
paren === 0 &&
/\s/.test(character) &&
beginsDeclaration(index)
) {
const declaration = value.slice(start, index).trim();
if (declaration) declarations.push(declaration);
while (index < value.length && /\s/.test(value[index])) index += 1;
start = index;
continue;
}
index += 1;
}
const declaration = value.slice(start).trim();
if (declaration) declarations.push(declaration);
return declarations;
}
function formatInlinePropsBlock(value, unit, depth) {
const match = /^props\s*\{([\s\S]*)\}$/.exec(value.trim());
if (!match) return null;
const declarations = splitPropDeclarations(match[1].trim());
if (declarations.length === 0) {
return [`${unit.repeat(depth)}props {`, `${unit.repeat(depth)}}`];
}
return [
`${unit.repeat(depth)}props {`,
...declarations.map((declaration) => `${unit.repeat(depth + 1)}${declaration}`),
`${unit.repeat(depth)}}`,
];
}
function findOpeningTagEnd(value) {
let quote = null;
let escaped = false;
@@ -347,6 +432,13 @@ function formatWrn(source, options = {}) {
index = collected.endIndex;
}
const inlineProps = formatInlinePropsBlock(value, unit, codeDepth + htmlDepth);
if (inlineProps) {
output.push(...inlineProps);
index += 1;
continue;
}
const leadingClosingBraces = countLeadingClosingBraces(value);
const lineCodeDepth = Math.max(0, codeDepth - leadingClosingBraces);
@@ -405,4 +497,5 @@ module.exports = {
formatWrn,
parseAttributes,
parseOpeningTag,
splitPropDeclarations,
};
+21
View File
@@ -0,0 +1,21 @@
"use strict";
const assert = require("node:assert");
const { test } = require("node:test");
const { formatWrn } = require("../src/formatter");
test("formats compact props blocks with one prop per line", () => {
const source = `component Header {\nprops { eyebrow = "" title = "" description = "" align = "start" class = "" }\nview { <header>{title}</header> }\n}\n`;
const expected = `component Header {\n props {\n eyebrow = ""\n title = ""\n description = ""\n align = "start"\n class = ""\n }\n view { <header>{title}</header> }\n}\n`;
assert.equal(formatWrn(source, { insertSpaces: true, tabSize: 2 }), expected);
});
test("preserves nested prop defaults while formatting", () => {
const source = `component Grid {\nprops { items = [{ label: "A" }, { label: "B" }] options = { gap: 4, dense: false } class = "" }\nview { <div/> }\n}\n`;
const formatted = formatWrn(source, { insertSpaces: true, tabSize: 2 });
assert.match(formatted, /items = \[\{ label: "A" \}, \{ label: "B" \}\]/);
assert.match(formatted, /options = \{ gap: 4, dense: false \}/);
assert.equal(formatWrn(formatted, { insertSpaces: true, tabSize: 2 }), formatted);
});
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ai",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/authz",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/cli",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"main": "src/index.ts",
"exports": {
+8
View File
@@ -759,6 +759,14 @@ const MIGRATIONS: Migration[] = [
// Language and shared UI behavior improve automatically after updating.
},
},
{
version: "0.2.77",
id: "ui-components-fix",
description: "Dev toolbar for optimization and developer.",
apply() {
// Language and shared UI behavior improve automatically after updating.
},
},
];
/** Release tooling uses this to require an explicit migration entry per version. */
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/compiler",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -295,7 +295,7 @@ export function parse(source: string): PageAst {
expect("eq");
hasDefault = true;
}
const defaultValue = hasDefault ? lx.readToLineEnd() : "undefined";
const defaultValue = hasDefault ? lx.readPropInitializer() : "undefined";
props.push({ name: pName, valueType, required: !hasDefault, default: defaultValue });
}
expect("rbrace");
+68
View File
@@ -138,6 +138,74 @@ export class Lexer {
return v;
}
/**
* Read a prop default initializer. The initializer may contain nested arrays,
* objects, calls, strings, or template literals. At top level it ends at a
* newline, the closing brace of the props block, or the next inline prop
* declaration (`name = ...` / `name: Type = ...`).
*/
readPropInitializer(): string {
const { src } = this;
while (this.pos < src.length && (src[this.pos] === " " || src[this.pos] === "\t")) {
this.pos++;
}
const start = this.pos;
let square = 0;
let brace = 0;
let paren = 0;
let angle = 0;
let quote: string | null = null;
const atTopLevel = () => square === 0 && brace === 0 && paren === 0 && angle === 0;
while (this.pos < src.length) {
const c = src[this.pos]!;
if (quote) {
this.pos++;
if (c === "\\" && this.pos < src.length) {
this.pos++;
} else if (c === quote) {
quote = null;
}
continue;
}
if (c === '"' || c === "'" || c === "`") {
quote = c;
this.pos++;
continue;
}
if (atTopLevel()) {
if (c === "\n" || c === "\r" || c === "}") break;
if (c === " " || c === "\t") {
let look = this.pos;
while (look < src.length && (src[look] === " " || src[look] === "\t")) look++;
const rest = src.slice(look);
if (/^[A-Za-z_][A-Za-z0-9_]*(?:\s*:[^=\r\n{}]+)?\s*=/.test(rest)) break;
}
}
if (c === "[") square++;
else if (c === "]" && square > 0) square--;
else if (c === "{") brace++;
else if (c === "}" && brace > 0) brace--;
else if (c === "(") paren++;
else if (c === ")" && paren > 0) paren--;
else if (c === "<") angle++;
else if (c === ">" && angle > 0) angle--;
this.pos++;
}
const value = src.slice(start, this.pos).trim();
if (!value) throw new LexError(`Expected a prop initializer at offset ${start}`);
return value;
}
/** Read the rest of the current line (used for `state x = <expr>`). */
readToLineEnd(): string {
const { src } = this;
@@ -0,0 +1,33 @@
import { describe, expect, test } from "bun:test";
import { parse, type PropDecl } from "../src/parser.ts";
const compact = (source: string) =>
parse(source).props.map(({ name, default: value }: PropDecl) => ({ name, value }));
describe("inline props", () => {
test("parses multiple props declared on one line", () => {
expect(
compact(
`component Example { props { eyebrow = "" title = "" description = "" align = "start" class = "" } view { <div></div> } }`,
),
).toEqual([
{ name: "eyebrow", value: '""' },
{ name: "title", value: '""' },
{ name: "description", value: '""' },
{ name: "align", value: '"start"' },
{ name: "class", value: '""' },
]);
});
test("preserves nested object and array defaults", () => {
expect(
compact(
`component Example { props { items = [{ label: "A" }, { label: "B" }] options = { gap: 4, dense: false } class = "" } view { <div></div> } }`,
),
).toEqual([
{ name: "items", value: '[{ label: "A" }, { label: "B" }]' },
{ name: "options", value: "{ gap: 4, dense: false }" },
{ name: "class", value: '""' },
]);
});
});
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/core",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/csr",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/db",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/dev-server",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/dev-toolbar",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"sideEffects": false,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/encryption",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/helpers",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/i18n",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/jwt",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/mobile",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/native",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/oauth",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/pubsub",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/queue",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/reactive",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/router",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ssr",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/styles",
"version": "0.2.76",
"version": "0.2.77",
"type": "module",
"main": "src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/test",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/tracking",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"main": "src/index.ts",
@@ -9,7 +9,43 @@ component AnalyticsDashboardPreview {
alt = ""
class = ""
}
view {
<article class="wire-card wire-catalog-card {class}">{#if image}<img src="{image}" alt="{alt}" class="wire-catalog-card__image" />{:else}<div role="img" aria-label="Communication performance chart trending upward over seven days" class="grid min-h-64 gap-4 rounded-xl border border-slate-200 bg-slate-50 p-5 dark:border-slate-800 dark:bg-slate-950/60"><div class="flex items-center justify-between"><span class="text-sm font-semibold">Delivery trend</span><span class="inline-flex items-center gap-1 text-xs font-bold text-emerald-500"><span class="icon-[lucide--trending-up] size-4" aria-hidden="true"></span>18.4%</span></div><svg viewBox="0 0 600 190" role="presentation" class="h-auto w-full overflow-visible"><defs><linearGradient id="wire-analytics-fill" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="currentColor" stop-opacity="0.28"></stop><stop offset="100%" stop-color="currentColor" stop-opacity="0"></stop></linearGradient></defs><g stroke="currentColor" stroke-opacity="0.12"><path d="M0 30H600M0 80H600M0 130H600M0 180H600"></path></g><path d="M0 157 C55 150 70 118 124 126 S205 152 255 103 S342 91 392 98 S470 67 515 74 S566 38 600 30 L600 190 L0 190 Z" fill="url(#wire-analytics-fill)" class="text-violet-500"></path><path d="M0 157 C55 150 70 118 124 126 S205 152 255 103 S342 91 392 98 S470 67 515 74 S566 38 600 30" fill="none" stroke="currentColor" stroke-width="5" stroke-linecap="round" class="text-violet-500"></path><g fill="currentColor" class="text-violet-500"><circle cx="124" cy="126" r="5"></circle><circle cx="255" cy="103" r="5"></circle><circle cx="392" cy="98" r="5"></circle><circle cx="515" cy="74" r="5"></circle><circle cx="600" cy="30" r="6"></circle></g></svg><div class="flex justify-between text-[0.6875rem] text-slate-500"><span>Mon</span><span>Tue</span><span>Wed</span><span>Thu</span><span>Fri</span><span>Sat</span><span>Sun</span></div></div>{/if}{#if eyebrow}<span class="wire-eyebrow">{eyebrow}</span>{/if}{#if title}<h3>{title}</h3>{/if}{#if description}<p>{description}</p>{/if}<slot />{#if href}<a href="{href}" class="wire-btn wire-btn--ghost">{actionLabel}</a>{/if}</article>
<section class="px-4 sm:px-6 lg:px-8 {class}">
<div class="mx-auto grid w-full max-w-7xl gap-8 overflow-hidden rounded-3xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-5 shadow-[var(--wire-shadow-md,0_12px_30px_rgb(0_0_0/0.08))] sm:p-7 lg:grid-cols-[1.25fr_0.75fr] lg:items-center lg:p-8">
<div>
{#if image}
<img src="{image}" alt="{alt}" class="aspect-[16/9] w-full rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] object-cover" />
{:else}
<div class="rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface-muted,#f8fafc)] p-4 sm:p-5" role="img" aria-label="Delivery trend rising over seven days">
<div class="flex items-center justify-between gap-4 text-sm">
<strong class="text-[var(--wire-color-text,#0f172a)]">Delivery trend</strong>
<span class="font-bold text-[var(--wire-color-success,#059669)]">↗ 18.4%</span>
</div>
<svg class="mt-4 h-auto w-full text-[var(--wire-color-primary,#059669)]" viewBox="0 0 700 250" aria-hidden="true">
<defs>
<linearGradient id="wire-analytics-area" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="currentColor" stop-opacity=".24"></stop>
<stop offset="100%" stop-color="currentColor" stop-opacity="0"></stop>
</linearGradient>
</defs>
<g fill="none" stroke="var(--wire-color-border,#e2e8f0)"><path d="M20 50H680M20 115H680M20 180H680M20 230H680"></path></g>
<path fill="url(#wire-analytics-area)" d="M20 210 C100 195 120 150 190 165 S310 195 370 120 S475 130 525 100 S610 90 680 32 L680 230 L20 230Z"></path>
<path fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" d="M20 210 C100 195 120 150 190 165 S310 195 370 120 S475 130 525 100 S610 90 680 32"></path>
</svg>
<div class="mt-2 flex justify-between text-[0.7rem] text-[var(--wire-color-text-muted,#64748b)]"><span>Mon</span><span>Tue</span><span>Wed</span><span>Thu</span><span>Fri</span><span>Sat</span><span>Sun</span></div>
</div>
{/if}
</div>
<div>
{#if eyebrow}<p class="m-0 text-xs font-bold uppercase tracking-[0.16em] text-[var(--wire-color-primary,#059669)]">{eyebrow}</p>{/if}
{#if title}<h2 class="mt-4 text-3xl font-semibold tracking-[-0.035em] text-[var(--wire-color-text,#0f172a)]">{title}</h2>{/if}
{#if description}<p class="mt-4 leading-7 text-[var(--wire-color-text-muted,#64748b)]">{description}</p>{/if}
<div class="mt-5"><slot /></div>
{#if href}<a href="{href}" class="mt-6 inline-flex items-center gap-2 font-semibold text-[var(--wire-color-primary,#059669)] no-underline">{actionLabel}<span aria-hidden="true">→</span></a>{/if}
</div>
</div>
</section>
}
}
+21 -2
View File
@@ -3,8 +3,27 @@ component ChannelCard {
title = ""
description = ""
href = ""
icon = "icon-[lucide--radio-tower]"
icon = ""
class = ""
}
view { <article class="wire-card wire-catalog-card wire-catalog-card--channel {class}"><span class="wire-catalog-card__icon"><span class="{icon} size-5" aria-hidden="true"></span></span>{#if title}<h3>{title}</h3>{/if}{#if description}<p>{description}</p>{/if}<slot />{#if href}<a href="{href}" class="wire-catalog-card__link"><span class="wire-visually-hidden">Open {title}</span></a>{/if}</article> }
view {
<article class="group flex h-full min-h-72 flex-col rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-6 shadow-[var(--wire-shadow-sm,0_1px_2px_rgb(0_0_0/0.05))] transition duration-200 hover:-translate-y-1 hover:border-[var(--wire-color-primary,#059669)] hover:shadow-[var(--wire-shadow-md,0_12px_30px_rgb(0_0_0/0.10))] {class}">
<div class="flex min-h-12 items-start justify-between gap-4">
{#if icon}
<span class="inline-grid h-12 w-12 shrink-0 place-items-center rounded-xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-primary-soft,#ecfdf5)] text-xl text-[var(--wire-color-primary,#059669)] {icon}" aria-hidden="true"></span>
{/if}
<div class="flex min-w-0 justify-end"><slot /></div>
</div>
{#if title}<h3 class="mt-5 text-xl font-semibold tracking-[-0.02em] text-[var(--wire-color-text,#0f172a)]">{title}</h3>{/if}
{#if description}<p class="mt-3 flex-1 leading-7 text-[var(--wire-color-text-muted,#64748b)]">{description}</p>{/if}
{#if href}
<a href="{href}" class="mt-6 inline-flex items-center justify-between gap-3 border-t border-[var(--wire-color-border,#e2e8f0)] pt-5 font-semibold text-[var(--wire-color-primary,#059669)] no-underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-primary,#059669)]" aria-label="Explore {title}">
<span>Explore {title}</span><span class="transition-transform group-hover:translate-x-0.5" aria-hidden="true">→</span>
</a>
{/if}
</article>
}
}
+32 -6
View File
@@ -1,11 +1,37 @@
component ChannelFlow {
props {
title = ""
value = ""
description = ""
summary = ""
loading = false
class = ""
}
view { <figure aria-label="{summary || title}" class="wire-card wire-catalog-visualization {class}"><figcaption><strong data-show="title">{title}</strong><span data-show="value" class="wire-metric__value">{value}</span><span data-show="description" class="wire-muted">{description}</span></figcaption><div data-show="loading" class="wire-skeleton wire-catalog-visualization__skeleton"></div><div data-show="!loading" class="wire-catalog-visualization__content"><slot /></div><p data-show="summary" class="wire-visually-hidden">{summary}</p></figure> }
view {
<div class="grid grid-cols-1 items-center gap-3 lg:grid-cols-[1fr_auto_1fr_auto_1.2fr_auto_1fr] {class}" role="img" aria-label="Customer event flows through profile and consent checks to communication channels, then delivery analytics and webhooks">
<div class="rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-4">
<span class="icon-[lucide--webhook] text-xl text-[var(--wire-color-primary,#059669)]" aria-hidden="true"></span>
<strong class="mt-3 block text-sm text-[var(--wire-color-text,#0f172a)]">Customer event</strong>
<small class="mt-1 block text-[var(--wire-color-text-muted,#64748b)]">order.shipped</small>
</div>
<span class="hidden text-center text-xl text-[var(--wire-color-primary,#059669)] lg:block" aria-hidden="true">→</span>
<div class="rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-4">
<span class="icon-[lucide--shield-check] text-xl text-[var(--wire-color-primary,#059669)]" aria-hidden="true"></span>
<strong class="mt-3 block text-sm text-[var(--wire-color-text,#0f172a)]">Profile + consent</strong>
<small class="mt-1 block text-[var(--wire-color-text-muted,#64748b)]">Eligibility checked</small>
</div>
<span class="hidden text-center text-xl text-[var(--wire-color-primary,#059669)] lg:block" aria-hidden="true">→</span>
<div class="grid grid-cols-2 gap-2 rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-3">
<span class="rounded-xl bg-[var(--wire-color-primary-soft,#ecfdf5)] px-3 py-2.5 text-center text-xs font-bold text-[var(--wire-color-primary,#059669)]">WhatsApp</span>
<span class="rounded-xl bg-[var(--wire-color-primary-soft,#ecfdf5)] px-3 py-2.5 text-center text-xs font-bold text-[var(--wire-color-primary,#059669)]">SMS</span>
<span class="rounded-xl bg-[var(--wire-color-primary-soft,#ecfdf5)] px-3 py-2.5 text-center text-xs font-bold text-[var(--wire-color-primary,#059669)]">Email</span>
<span class="rounded-xl bg-[var(--wire-color-primary-soft,#ecfdf5)] px-3 py-2.5 text-center text-xs font-bold text-[var(--wire-color-primary,#059669)]">Voice</span>
</div>
<span class="hidden text-center text-xl text-[var(--wire-color-primary,#059669)] lg:block" aria-hidden="true">→</span>
<div class="rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-4">
<span class="icon-[lucide--chart-no-axes-combined] text-xl text-[var(--wire-color-primary,#059669)]" aria-hidden="true"></span>
<strong class="mt-3 block text-sm text-[var(--wire-color-text,#0f172a)]">Delivery + analytics</strong>
<small class="mt-1 block text-[var(--wire-color-text-muted,#64748b)]">Webhook emitted</small>
</div>
</div>
}
}
+5 -3
View File
@@ -1,9 +1,11 @@
component Cluster {
props {
gap = "4"
className = ""
class = ""
}
view {
<div class="flex flex-wrap items-center gap-{gap} {className}"><slot /></div>
<div class="flex flex-wrap items-center gap-3 {class}">
<slot />
</div>
}
}
+18 -4
View File
@@ -1,12 +1,26 @@
component CodeBlock {
props {
class = ""
language = "text"
filename = ""
title = ""
code = ""
copyable = true
class = ""
}
state copied = false
view {
<div class="min-w-0 overflow-hidden rounded-2xl border border-slate-800 bg-slate-950 text-slate-100 shadow-2xl shadow-slate-950/20 {class}"><div class="flex min-h-12 items-center justify-between gap-4 border-b border-slate-800 px-4 text-xs text-slate-400"><span class="inline-flex min-w-0 items-center gap-2 truncate"><span class="icon-[lucide--terminal] size-4 shrink-0" aria-hidden="true"></span>{filename || language}</span><button type="button" @click="navigator.clipboard.writeText(code); copied = true" class="inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-slate-700 px-2.5 py-1.5 font-semibold text-slate-300 transition hover:border-slate-600 hover:bg-slate-800 hover:text-white"><span class="{copied ? 'icon-[lucide--check]' : 'icon-[lucide--copy]'} size-3.5" aria-hidden="true"></span>{copied ? 'Copied' : 'Copy'}</button></div><pre class="m-0 max-w-full overflow-x-auto whitespace-pre-wrap break-words p-5 font-mono text-[0.8125rem] leading-6 sm:whitespace-pre"><code>{code}</code></pre></div>
<section class="overflow-hidden bg-[var(--wire-color-code-background,#020617)] text-[var(--wire-color-code-text,#e2e8f0)] {class}">
<header class="flex items-center justify-between gap-4 border-b border-[var(--wire-color-code-border,#1e293b)] px-4 py-3 text-xs text-[var(--wire-color-code-muted,#94a3b8)] sm:px-5">
<span class="inline-flex items-center gap-2 font-medium">
<span class="icon-[lucide--terminal]" aria-hidden="true"></span>
{#if title}{title}{:else}{language}{/if}
</span>
{#if copyable}
<button type="button" data-copy-code="{code}" class="inline-flex items-center gap-2 rounded-lg border border-[var(--wire-color-code-border,#334155)] px-3 py-1.5 font-semibold text-[var(--wire-color-code-text,#e2e8f0)] transition hover:bg-[var(--wire-color-code-surface,#0f172a)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-primary,#059669)]">
<span class="icon-[lucide--copy]" aria-hidden="true"></span>Copy
</button>
{/if}
</header>
<pre class="m-0 max-w-full overflow-x-auto p-5 text-sm leading-7"><code>{code}</code></pre>
</section>
}
}
+6 -8
View File
@@ -1,13 +1,11 @@
component CodeTabs {
props {
eyebrow = ""
title = ""
description = ""
href = ""
actionLabel = "Learn more"
image = ""
alt = ""
class = ""
}
view { <article class="wire-card wire-catalog-card {class}">{#if image}<img src="{image}" alt="{alt}" class="wire-catalog-card__image" />{/if}{#if eyebrow}<span class="wire-eyebrow">{eyebrow}</span>{/if}{#if title}<h3>{title}</h3>{/if}{#if description}<p>{description}</p>{/if}<slot />{#if href}<a href="{href}" class="wire-btn wire-btn--ghost">{actionLabel}</a>{/if}</article> }
view {
<div class="overflow-hidden rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] shadow-[var(--wire-shadow-sm,0_1px_2px_rgb(0_0_0/0.05))] {class}">
<slot />
</div>
}
}
+20 -1
View File
@@ -9,5 +9,24 @@ component FeatureTabs {
alt = ""
class = ""
}
view { <article class="wire-card wire-catalog-card {class}">{#if image}<img src="{image}" alt="{alt}" class="wire-catalog-card__image" />{/if}{#if eyebrow}<span class="wire-eyebrow">{eyebrow}</span>{/if}{#if title}<h3>{title}</h3>{/if}{#if description}<p>{description}</p>{/if}<slot />{#if href}<a href="{href}" class="wire-btn wire-btn--ghost">{actionLabel}</a>{/if}</article> }
view {
<article class="group flex h-full min-h-72 flex-col overflow-hidden rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] shadow-[var(--wire-shadow-sm,0_1px_2px_rgb(0_0_0/0.05))] transition duration-200 hover:-translate-y-1 hover:border-[var(--wire-color-primary,#059669)] hover:shadow-[var(--wire-shadow-md,0_12px_30px_rgb(0_0_0/0.10))] {class}">
{#if image}
<img src="{image}" alt="{alt}" class="aspect-[16/9] w-full border-b border-[var(--wire-color-border,#e2e8f0)] object-cover" />
{/if}
<div class="flex flex-1 flex-col p-6">
{#if eyebrow}<p class="m-0 text-xs font-bold uppercase tracking-[0.14em] text-[var(--wire-color-primary,#059669)]">{eyebrow}</p>{/if}
{#if title}<h3 class="mt-4 text-xl font-semibold leading-snug tracking-[-0.02em] text-[var(--wire-color-text,#0f172a)]">{title}</h3>{/if}
{#if description}<p class="mt-3 flex-1 leading-7 text-[var(--wire-color-text-muted,#64748b)]">{description}</p>{/if}
<div class="mt-5"><slot /></div>
{#if href}
<a href="{href}" class="mt-6 inline-flex items-center gap-2 font-semibold text-[var(--wire-color-primary,#059669)] no-underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-primary,#059669)]">
<span>{actionLabel}</span><span class="transition-transform group-hover:translate-x-0.5" aria-hidden="true">→</span>
</a>
{/if}
</div>
</article>
}
}
+26 -2
View File
@@ -1,11 +1,35 @@
component FinalCTA {
props {
label = "Action"
label = "Get started"
href = ""
type = "button"
variant = "primary"
disabled = false
class = ""
}
view { <span class="wire-catalog-action {class}">{#if href}<a href="{href}" class="wire-btn wire-btn--{variant}">{label}<slot /></a>{:else}<button type="{type}" disabled="{disabled}" class="wire-btn wire-btn--{variant}">{label}<slot /></button>{/if}</span> }
view {
<span class="contents {class}">
{#if href}
<a
href="{href}"
class=' group inline-flex min-h-11 items-center justify-center gap-2 rounded-xl px-5 py-2.5 text-sm font-semibold no-underline transition duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-primary,#059669)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--wire-color-background,#ffffff)] {variant === "primary" ? "bg-[var(--wire-color-primary,#059669)] text-[var(--wire-color-primary-contrast,#ffffff)] hover:bg-[var(--wire-color-primary-hover,#047857)]" : "border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] text-[var(--wire-color-text,#0f172a)] hover:border-[var(--wire-color-primary,#059669)] hover:text-[var(--wire-color-primary,#059669)]"} '
aria-disabled="{disabled}"
>
<span>{label}</span>
<span class="transition-transform duration-200 group-hover:translate-x-0.5" aria-hidden="true">→</span>
<slot />
</a>
{:else}
<button
type="{type}"
disabled="{disabled}"
class=' group inline-flex min-h-11 items-center justify-center gap-2 rounded-xl px-5 py-2.5 text-sm font-semibold transition duration-200 disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-primary,#059669)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--wire-color-background,#ffffff)] {variant === "primary" ? "bg-[var(--wire-color-primary,#059669)] text-[var(--wire-color-primary-contrast,#ffffff)] hover:bg-[var(--wire-color-primary-hover,#047857)]" : "border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] text-[var(--wire-color-text,#0f172a)] hover:border-[var(--wire-color-primary,#059669)] hover:text-[var(--wire-color-primary,#059669)]"} '
>
<span>{label}</span>
<slot />
</button>
{/if}
</span>
}
}
@@ -6,5 +6,30 @@ component MarketingSectionHeader {
align = "start"
class = ""
}
view { <section class="wire-catalog-section wire-text--{align} {class}"><header data-show="eyebrow || title || description"><span data-show="eyebrow" class="wire-eyebrow">{eyebrow}</span><h2 data-show="title">{title}</h2><p data-show="description" class="wire-muted">{description}</p></header><slot /></section> }
view {
<section class="px-4 py-16 sm:px-6 sm:py-20 lg:px-8 {class}">
<div class="mx-auto w-full max-w-7xl">
<header
class="max-w-3xl"
class:mx-auto='{align === "center"}'
class:text-center='{align === "center"}'
>
{#if eyebrow}
<p class="mb-3 text-xs font-bold uppercase tracking-[0.16em] text-[var(--wire-color-primary,#059669)] sm:text-sm">{eyebrow}</p>
{/if}
{#if title}
<h2 class="m-0 text-3xl font-semibold tracking-[-0.035em] text-[var(--wire-color-text,#0f172a)] sm:text-4xl">{title}</h2>
{/if}
{#if description}
<p class="mt-5 text-base leading-8 text-[var(--wire-color-text-muted,#64748b)] sm:text-lg">{description}</p>
{/if}
</header>
<div class="mt-8">
<slot />
</div>
</div>
</section>
}
}
+23 -2
View File
@@ -1,8 +1,29 @@
component MetricGrid {
props {
label = "Key metrics"
label = "Platform metrics"
metrics = []
class = ""
}
view { <section aria-label="{label}" class="wire-metric-grid {class}">{#each metrics as metric}<article class="wire-metric"><p class="wire-metric__value">{metric.value}</p><p class="wire-metric__label">{metric.label}</p><p data-show="metric.description" class="wire-metric__description">{metric.description}</p></article>{/each}</section> }
view {
<section class="px-4 sm:px-6 lg:px-8 {class}" aria-label="{label}">
<div class="mx-auto grid w-full max-w-7xl grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
{#each metrics as metric}
<article class="flex min-h-40 flex-col justify-center rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-6 shadow-[var(--wire-shadow-sm,0_1px_2px_rgb(0_0_0/0.05))]">
<strong class="text-3xl font-semibold leading-none tracking-[-0.04em] text-[var(--wire-color-text,#0f172a)] sm:text-4xl">
{metric.value}
</strong>
<span class="mt-4 font-semibold text-[var(--wire-color-text,#0f172a)]">{metric.label}</span>
{#if metric.description}
<p class="mt-2 text-sm leading-6 text-[var(--wire-color-text-muted,#64748b)]">{metric.description}</p>
{/if}
</article>
{:empty}
<p class="col-span-full rounded-2xl border border-dashed border-[var(--wire-color-border,#e2e8f0)] p-8 text-center text-[var(--wire-color-text-muted,#64748b)]">
No metrics available.
</p>
{/each}
</div>
</section>
}
}
@@ -7,5 +7,29 @@ component ProductArchitectureDiagram {
loading = false
class = ""
}
view { <figure aria-label="{summary || title}" class="wire-card wire-catalog-visualization {class}"><figcaption><strong data-show="title">{title}</strong><span data-show="value" class="wire-metric__value">{value}</span><span data-show="description" class="wire-muted">{description}</span></figcaption><div data-show="loading" class="wire-skeleton wire-catalog-visualization__skeleton"></div><div data-show="!loading" class="wire-catalog-visualization__content"><slot /></div><p data-show="summary" class="wire-visually-hidden">{summary}</p></figure> }
view {
<section class="overflow-hidden rounded-3xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] shadow-[var(--wire-shadow-md,0_12px_30px_rgb(0_0_0/0.08))] {class}" aria-label="{title}">
<header class="flex flex-col gap-4 border-b border-[var(--wire-color-border,#e2e8f0)] p-6 sm:flex-row sm:items-start sm:justify-between lg:p-8">
<div>
{#if title}<p class="m-0 font-semibold text-[var(--wire-color-text,#0f172a)]">{title}</p>{/if}
{#if value}<strong class="mt-3 block text-3xl font-semibold tracking-[-0.04em] text-[var(--wire-color-text,#0f172a)] sm:text-4xl">{value}</strong>{/if}
{#if description}<p class="mt-3 max-w-2xl leading-7 text-[var(--wire-color-text-muted,#64748b)]">{description}</p>{/if}
</div>
{#if loading}
<span class="inline-flex w-max items-center gap-2 rounded-full bg-[var(--wire-color-surface-muted,#f8fafc)] px-3 py-1.5 text-xs font-semibold text-[var(--wire-color-text-muted,#64748b)]">
<span class="h-2 w-2 animate-pulse rounded-full bg-[var(--wire-color-primary,#059669)]"></span>Loading
</span>
{/if}
</header>
<div class="bg-[var(--wire-color-surface-muted,#f8fafc)] p-4 sm:p-6 lg:p-8 empty:hidden">
<slot />
</div>
{#if summary}
<p class="m-0 border-t border-[var(--wire-color-border,#e2e8f0)] px-6 py-5 text-sm leading-6 text-[var(--wire-color-text-muted,#64748b)] lg:px-8">{summary}</p>
{/if}
</section>
}
}
+19 -4
View File
@@ -1,12 +1,27 @@
component ProductCard {
props {
eyebrow = "Product"
title = "Product name"
eyebrow = ""
title = ""
description = ""
href = "#"
href = ""
actionLabel = "Learn more"
status = ""
class = ""
}
view { <article class="wire-product-card {class}"><div class="wire-product-card__meta"><span class="wire-eyebrow">{eyebrow}</span><span data-show="status" class="wire-badge">{status}</span></div><h3>{title}</h3><p>{description}</p><a href="{href}" class="wire-product-card__link">{actionLabel}<span aria-hidden="true"> →</span></a></article> }
view {
<article class="group flex h-full min-h-72 flex-col rounded-2xl border border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface,#ffffff)] p-6 shadow-[var(--wire-shadow-sm,0_1px_2px_rgb(0_0_0/0.05))] transition duration-200 hover:-translate-y-1 hover:border-[var(--wire-color-primary,#059669)] hover:shadow-[var(--wire-shadow-md,0_12px_30px_rgb(0_0_0/0.10))] {class}">
<div class="flex min-h-7 items-start justify-between gap-4">
{#if eyebrow}<span class="text-xs font-bold uppercase tracking-[0.14em] text-[var(--wire-color-primary,#059669)]">{eyebrow}</span>{/if}
{#if status}<span class="shrink-0 rounded-full bg-[var(--wire-color-surface-muted,#f8fafc)] px-2.5 py-1 text-[0.7rem] font-bold text-[var(--wire-color-text-muted,#64748b)]">{status}</span>{/if}
</div>
{#if title}<h3 class="mt-5 text-xl font-semibold tracking-[-0.02em] text-[var(--wire-color-text,#0f172a)]">{title}</h3>{/if}
{#if description}<p class="mt-3 flex-1 leading-7 text-[var(--wire-color-text-muted,#64748b)]">{description}</p>{/if}
{#if href}
<a href="{href}" class="mt-6 inline-flex items-center gap-2 border-t border-[var(--wire-color-border,#e2e8f0)] pt-5 font-semibold text-[var(--wire-color-primary,#059669)] no-underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-primary,#059669)]">
<span>{actionLabel}</span><span class="transition-transform group-hover:translate-x-0.5" aria-hidden="true">→</span>
</a>
{/if}
</article>
}
}
+19 -1
View File
@@ -6,5 +6,23 @@ component ProductGrid {
emptyText = "No items available."
class = ""
}
view { <section class="wire-catalog-collection {class}"><header data-show="title || description"><h2 data-show="title">{title}</h2><p data-show="description">{description}</p></header><div data-show="!empty" role="list" class="wire-catalog-collection__items"><slot /></div><p data-show="empty" role="status" class="wire-muted">{emptyText}</p></section> }
view {
<section class="px-4 sm:px-6 lg:px-8 {class}">
<div class="mx-auto w-full max-w-7xl">
{#if title}<h2 class="m-0 text-3xl font-semibold tracking-[-0.035em] text-[var(--wire-color-text,#0f172a)]">{title}</h2>{/if}
{#if description}<p class="mt-4 max-w-3xl leading-7 text-[var(--wire-color-text-muted,#64748b)]">{description}</p>{/if}
{#if empty}
<div class="mt-8 rounded-2xl border border-dashed border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface-muted,#f8fafc)] p-10 text-center text-[var(--wire-color-text-muted,#64748b)]">
{emptyText}
</div>
{:else}
<div class="mt-8 grid grid-cols-1 items-stretch gap-5 md:grid-cols-2 xl:grid-cols-3 [&>*]:min-w-0 [&>*]:h-full">
<slot />
</div>
{/if}
</div>
</section>
}
}
+46 -1
View File
@@ -6,5 +6,50 @@ component ProductHero {
align = "start"
class = ""
}
view { <section class="wire-catalog-section wire-text--{align} {class}"><header data-show="eyebrow || title || description"><span data-show="eyebrow" class="wire-eyebrow">{eyebrow}</span><h2 data-show="title">{title}</h2><p data-show="description" class="wire-muted">{description}</p></header><slot /></section> }
view {
<section
class="
relative isolate overflow-hidden border-b border-[var(--wire-color-border,#e2e8f0)]
bg-[var(--wire-color-background,#ffffff)] px-4 py-16 sm:px-6 sm:py-20 lg:px-8 lg:py-24
{class}
"
>
<div
class="pointer-events-none absolute inset-0 -z-10 opacity-80"
style="background: radial-gradient(circle at 16% 0%, color-mix(in srgb, var(--wire-color-primary, #059669) 16%, transparent), transparent 36%);"
aria-hidden="true"
></div>
<div class="mx-auto w-full max-w-7xl">
<div
class="max-w-4xl"
class:mx-auto='{align === "center"}'
class:text-center='{align === "center"}'
>
{#if eyebrow}
<p class="mb-4 text-xs font-bold uppercase tracking-[0.18em] text-[var(--wire-color-primary,#059669)] sm:text-sm">
{eyebrow}
</p>
{/if}
{#if title}
<h1 class="m-0 max-w-[18ch] text-4xl font-semibold leading-[1.05] tracking-[-0.045em] text-[var(--wire-color-text,#0f172a)] sm:text-5xl lg:text-6xl" class:mx-auto='{align === "center"}'>
{title}
</h1>
{/if}
{#if description}
<p class="mt-6 max-w-3xl text-base leading-8 text-[var(--wire-color-text-muted,#64748b)] sm:text-lg" class:mx-auto='{align === "center"}'>
{description}
</p>
{/if}
</div>
<div class="mt-8 space-y-8">
<slot />
</div>
</div>
</section>
}
}
+15 -3
View File
@@ -1,6 +1,18 @@
component ProductPageShell {
props {
class = ""
props { class = "" }
view {
<main
class="
min-h-screen w-full overflow-x-clip
bg-[var(--wire-color-background,#ffffff)]
font-[var(--wire-font-sans,ui-sans-serif,system-ui,sans-serif)]
text-[var(--wire-color-text,#0f172a)]
antialiased
{class}
"
>
<slot />
</main>
}
view { <div class="wire-page-shell wire-page-shell--product {class}"><slot /></div> }
}
+11 -3
View File
@@ -1,8 +1,16 @@
component ProductStatusBadge {
props {
label = "ProductStatus"
variant = "default"
label = "Available"
status = ""
class = ""
}
view { <span class="wire-badge wire-badge--{variant} wire-catalog-badge wire-catalog-badge--productstatusbadge {class}">{label}<slot /></span> }
view {
<span
class=' inline-flex w-max items-center gap-1.5 rounded-full border px-2.5 py-1 text-[0.7rem] font-bold leading-none {status === "warning" ? "border-[var(--wire-color-warning,#d97706)] bg-[var(--wire-color-warning-soft,#fffbeb)] text-[var(--wire-color-warning,#d97706)]" : status === "muted" ? "border-[var(--wire-color-border,#e2e8f0)] bg-[var(--wire-color-surface-muted,#f8fafc)] text-[var(--wire-color-text-muted,#64748b)]" : "border-[var(--wire-color-primary,#059669)] bg-[var(--wire-color-primary-soft,#ecfdf5)] text-[var(--wire-color-primary,#059669)]"} {class} '
>
<span class="h-1.5 w-1.5 rounded-full bg-current" aria-hidden="true"></span>
{label}
</span>
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ui",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/uploader",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/validation",
"version": "0.2.76",
"version": "0.2.77",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,7 +1,7 @@
import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
const version = "0.2.76";
const version = "0.2.77";
const dependencyGroups = [
"dependencies",