diff --git a/.publish/ai/package.json b/.publish/ai/package.json index c968bd09..9ec3ee5b 100644 --- a/.publish/ai/package.json +++ b/.publish/ai/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/ai", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.", "license": "MIT", diff --git a/.publish/authz/package.json b/.publish/authz/package.json index 6d008814..9ce1e234 100644 --- a/.publish/authz/package.json +++ b/.publish/authz/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/authz", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/authz — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/cli/package.json b/.publish/cli/package.json index ef0273d8..b0a179d0 100644 --- a/.publish/cli/package.json +++ b/.publish/cli/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/cli", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/cli — part of the WrNexus framework.", "license": "MIT", @@ -28,18 +28,18 @@ "wrnexus": "./dist/index.js" }, "dependencies": { - "@wrnexus/core": "^0.5.11", - "@wrnexus/router": "^0.5.11", - "@wrnexus/csr": "^0.5.11", - "@wrnexus/compiler": "^0.5.11", - "@wrnexus/styles": "^0.5.11", - "@wrnexus/dev-server": "^0.5.11", - "@wrnexus/ui": "^0.5.11", - "@wrnexus/validation": "^0.5.11", - "@wrnexus/i18n": "^0.5.11", - "@wrnexus/db": "^0.5.11", - "@wrnexus/plugin": "^0.5.11", - "@wrnexus/syntax": "^0.5.11" + "@wrnexus/core": "^0.5.12", + "@wrnexus/router": "^0.5.12", + "@wrnexus/csr": "^0.5.12", + "@wrnexus/compiler": "^0.5.12", + "@wrnexus/styles": "^0.5.12", + "@wrnexus/dev-server": "^0.5.12", + "@wrnexus/ui": "^0.5.12", + "@wrnexus/validation": "^0.5.12", + "@wrnexus/i18n": "^0.5.12", + "@wrnexus/db": "^0.5.12", + "@wrnexus/plugin": "^0.5.12", + "@wrnexus/syntax": "^0.5.12" }, "files": [ "dist" diff --git a/.publish/compiler/package.json b/.publish/compiler/package.json index 5d0fe2c0..12e08b29 100644 --- a/.publish/compiler/package.json +++ b/.publish/compiler/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/compiler", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/compiler — part of the WrNexus framework.", "license": "MIT", @@ -21,7 +21,7 @@ } }, "dependencies": { - "@wrnexus/syntax": "^0.5.11" + "@wrnexus/syntax": "^0.5.12" }, "files": [ "dist" diff --git a/.publish/core/package.json b/.publish/core/package.json index 08b72815..7196af0d 100644 --- a/.publish/core/package.json +++ b/.publish/core/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/core", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/core — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/csr/package.json b/.publish/csr/package.json index d1734bdc..1db88575 100644 --- a/.publish/csr/package.json +++ b/.publish/csr/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/csr", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/csr — part of the WrNexus framework.", "license": "MIT", @@ -21,7 +21,7 @@ } }, "dependencies": { - "@wrnexus/core": "^0.5.11" + "@wrnexus/core": "^0.5.12" }, "files": [ "dist" diff --git a/.publish/db/package.json b/.publish/db/package.json index 47d37264..1e823ea2 100644 --- a/.publish/db/package.json +++ b/.publish/db/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/db", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/db — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/dev-server/package.json b/.publish/dev-server/package.json index a7186bd7..c02c3d94 100644 --- a/.publish/dev-server/package.json +++ b/.publish/dev-server/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/dev-server", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/dev-server — part of the WrNexus framework.", "license": "MIT", @@ -25,20 +25,20 @@ } }, "dependencies": { - "@wrnexus/core": "^0.5.11", - "@wrnexus/dev-toolbar": "^0.5.11", - "@wrnexus/router": "^0.5.11", - "@wrnexus/ssr": "^0.5.11", - "@wrnexus/csr": "^0.5.11", - "@wrnexus/compiler": "^0.5.11", - "@wrnexus/styles": "^0.5.11", - "@wrnexus/ui": "^0.5.11", - "@wrnexus/validation": "^0.5.11", - "@wrnexus/i18n": "^0.5.11", - "@wrnexus/db": "^0.5.11", - "@wrnexus/pubsub": "^0.5.11", - "@wrnexus/uploader": "^0.5.11", - "@wrnexus/plugin": "^0.5.11" + "@wrnexus/core": "^0.5.12", + "@wrnexus/dev-toolbar": "^0.5.12", + "@wrnexus/router": "^0.5.12", + "@wrnexus/ssr": "^0.5.12", + "@wrnexus/csr": "^0.5.12", + "@wrnexus/compiler": "^0.5.12", + "@wrnexus/styles": "^0.5.12", + "@wrnexus/ui": "^0.5.12", + "@wrnexus/validation": "^0.5.12", + "@wrnexus/i18n": "^0.5.12", + "@wrnexus/db": "^0.5.12", + "@wrnexus/pubsub": "^0.5.12", + "@wrnexus/uploader": "^0.5.12", + "@wrnexus/plugin": "^0.5.12" }, "files": [ "dist" diff --git a/.publish/dev-toolbar/package.json b/.publish/dev-toolbar/package.json index c62e6409..636c0a27 100644 --- a/.publish/dev-toolbar/package.json +++ b/.publish/dev-toolbar/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/dev-toolbar", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/dev-toolbar — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/encryption/package.json b/.publish/encryption/package.json index b77bceb7..8e406094 100644 --- a/.publish/encryption/package.json +++ b/.publish/encryption/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/encryption", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/encryption — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/helpers/package.json b/.publish/helpers/package.json index e6024211..14ddfb3a 100644 --- a/.publish/helpers/package.json +++ b/.publish/helpers/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/helpers", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "Safe convenience helpers for WrNexus request contexts and common application flows.", "license": "MIT", @@ -21,7 +21,7 @@ } }, "dependencies": { - "@wrnexus/core": "^0.5.11" + "@wrnexus/core": "^0.5.12" }, "files": [ "dist" diff --git a/.publish/i18n/package.json b/.publish/i18n/package.json index 294cd86e..b683e3f0 100644 --- a/.publish/i18n/package.json +++ b/.publish/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/i18n", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/i18n — part of the WrNexus framework.", "license": "MIT", @@ -21,7 +21,7 @@ } }, "dependencies": { - "@wrnexus/core": "^0.5.11" + "@wrnexus/core": "^0.5.12" }, "files": [ "dist" diff --git a/.publish/jwt/package.json b/.publish/jwt/package.json index 3279d10f..6a976a1c 100644 --- a/.publish/jwt/package.json +++ b/.publish/jwt/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/jwt", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/jwt — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/mobile/package.json b/.publish/mobile/package.json index e3727a8a..b7a77e9f 100644 --- a/.publish/mobile/package.json +++ b/.publish/mobile/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/mobile", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/mobile — part of the WrNexus framework.", "license": "MIT", @@ -21,7 +21,7 @@ } }, "dependencies": { - "@wrnexus/native": "^0.5.11" + "@wrnexus/native": "^0.5.12" }, "files": [ "dist" diff --git a/.publish/native/package.json b/.publish/native/package.json index dd31a8cd..3d3f1210 100644 --- a/.publish/native/package.json +++ b/.publish/native/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/native", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/native — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/oauth/package.json b/.publish/oauth/package.json index b9e2b743..09fff47d 100644 --- a/.publish/oauth/package.json +++ b/.publish/oauth/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/oauth", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/oauth — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/plugin/package.json b/.publish/plugin/package.json index 32c9d1de..e6c31634 100644 --- a/.publish/plugin/package.json +++ b/.publish/plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/plugin", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/plugin — part of the WrNexus framework.", "license": "MIT", @@ -33,7 +33,7 @@ } }, "dependencies": { - "@wrnexus/syntax": "^0.5.11" + "@wrnexus/syntax": "^0.5.12" }, "files": [ "dist" diff --git a/.publish/pubsub/package.json b/.publish/pubsub/package.json index 10892c0c..0383c221 100644 --- a/.publish/pubsub/package.json +++ b/.publish/pubsub/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/pubsub", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/pubsub — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/queue/package.json b/.publish/queue/package.json index 0dfcd1bd..e1c39b2f 100644 --- a/.publish/queue/package.json +++ b/.publish/queue/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/queue", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/queue — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/reactive/package.json b/.publish/reactive/package.json index 7ab4036e..43f58c04 100644 --- a/.publish/reactive/package.json +++ b/.publish/reactive/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/reactive", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/reactive — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/router/package.json b/.publish/router/package.json index 95296d63..78a97757 100644 --- a/.publish/router/package.json +++ b/.publish/router/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/router", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/router — part of the WrNexus framework.", "license": "MIT", @@ -21,8 +21,8 @@ } }, "dependencies": { - "@wrnexus/compiler": "^0.5.11", - "@wrnexus/core": "^0.5.11" + "@wrnexus/compiler": "^0.5.12", + "@wrnexus/core": "^0.5.12" }, "files": [ "dist" diff --git a/.publish/ssr/package.json b/.publish/ssr/package.json index 168dca66..b0641cd5 100644 --- a/.publish/ssr/package.json +++ b/.publish/ssr/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/ssr", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/ssr — part of the WrNexus framework.", "license": "MIT", @@ -21,7 +21,7 @@ } }, "dependencies": { - "@wrnexus/core": "^0.5.11" + "@wrnexus/core": "^0.5.12" }, "files": [ "dist" diff --git a/.publish/styles/package.json b/.publish/styles/package.json index fa91e121..6c036ad9 100644 --- a/.publish/styles/package.json +++ b/.publish/styles/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/styles", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/styles — part of the WrNexus framework.", "license": "MIT", @@ -21,9 +21,9 @@ } }, "dependencies": { - "@wrnexus/uploader": "^0.5.11", - "@wrnexus/core": "^0.5.11", - "@wrnexus/plugin": "^0.5.11" + "@wrnexus/uploader": "^0.5.12", + "@wrnexus/core": "^0.5.12", + "@wrnexus/plugin": "^0.5.12" }, "files": [ "dist" diff --git a/.publish/syntax/package.json b/.publish/syntax/package.json index 37f088f8..07836fc4 100644 --- a/.publish/syntax/package.json +++ b/.publish/syntax/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/syntax", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/syntax — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/test/package.json b/.publish/test/package.json index 8e694ef1..98cb679b 100644 --- a/.publish/test/package.json +++ b/.publish/test/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/test", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/test — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/tracking/package.json b/.publish/tracking/package.json index 612fa0a1..9c8cb078 100644 --- a/.publish/tracking/package.json +++ b/.publish/tracking/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/tracking", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/tracking — part of the WrNexus framework.", "license": "MIT", diff --git a/.publish/ui/COMPONENTS.md b/.publish/ui/COMPONENTS.md index c845e5c9..bb322369 100644 --- a/.publish/ui/COMPONENTS.md +++ b/.publish/ui/COMPONENTS.md @@ -1,6 +1,6 @@ # WRNexus UI component reference -This reference is generated from the 90 packaged `.wrn` component sources. Props marked required have no default; all others show their runtime default. +This reference is generated from the 108 packaged `.wrn` component sources. Props marked required have no default; all others show their runtime default. ## Advanced-forms @@ -56,7 +56,7 @@ Theme-aware, responsive search box component. - Mount: `data-component="SearchBox"` - Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Search Box"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "search"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""` - Slots: None -- Events: `input`, `change`, `search`, `submit`, `clear` +- Events: None ### StrongPassword @@ -222,6 +222,15 @@ Theme-aware, responsive file upload progress component. - Slots: None - Events: `cancel`, `retry`, `complete` +### HeroActions + +Responsive action group for hero and call-to-action sections. + +- Mount: `data-component="HeroActions"` +- Props: `actions: string = []`, `align: string = "left"`, `orientation: string = "horizontal"`, `stackOnMobile: boolean = true`, `fullWidthMobile: boolean = true`, `size: string = "default"`, `color: string = "primary"`, `class: string = ""` +- Slots: `default` +- Events: None + ### LegendIndicator Theme-aware, responsive legend indicator component. @@ -238,7 +247,7 @@ Theme-aware, responsive list component. - Mount: `data-component="List"` - Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "List"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` - Slots: `default` -- Events: `select`, `click` +- Events: None ### ListGroup @@ -256,7 +265,7 @@ Theme-aware, responsive marquee component. - Mount: `data-component="Marquee"` - Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Marquee"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` - Slots: `default` -- Events: `pause`, `resume` +- Events: None ### Progress @@ -310,7 +319,7 @@ Theme-aware, responsive timeline component. - Mount: `data-component="Timeline"` - Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Timeline"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` - Slots: `default` -- Events: `select` +- Events: None ### Toast @@ -332,6 +341,78 @@ Theme-aware, responsive tree view component. ## Blocks +### AnnouncementBar + +Accessible public announcement, emergency, maintenance, or status bar. + +- Mount: `data-component="AnnouncementBar"` +- Props: `badge: string = ""`, `badgeIcon: string = ""`, `message: string = "Announcement"`, `description: string = ""`, `icon: string = "icon-[lucide--megaphone]"`, `actionLabel: string = ""`, `actionHref: string = ""`, `actionIcon: string = ""`, `dismissible: boolean = false`, `dismissLabel: string = "Dismiss announcement"`, `sticky: boolean = false`, `compact: boolean = false`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "soft"`, `role: string = "status"`, `live: string = "polite"`, `class: string = ""` +- Slots: None +- Events: None + +### CTASection + +Reusable closing call-to-action section with primary and secondary actions. + +- Mount: `data-component="CTASection"` +- Props: `eyebrow: string = ""`, `title: string = "Ready to get started?"`, `description: string = ""`, `icon: string = ""`, `align: string = "center"`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "solid"`, `primaryLabel: string = "Get started"`, `primaryHref: string = "#"`, `primaryIcon: string = ""`, `secondaryLabel: string = ""`, `secondaryHref: string = ""`, `secondaryIcon: string = ""`, `backgroundImage: string = ""`, `maxWidth: string = "xl"`, `class: string = ""` +- Slots: `default`, `actions`, `visual`, `footer` +- Events: None + +### FeatureCard + +Reusable linked feature or service card with icon, badge, description, and action. + +- Mount: `data-component="FeatureCard"` +- Props: `icon: string = ""`, `title: string = "Feature"`, `description: string = ""`, `href: string = ""`, `actionLabel: string = "Learn more"`, `actionIcon: string = ""`, `badge: string = ""`, `badgeColor: string = "primary"`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `hover: string = "lift"`, `align: string = "left"`, `disabled: boolean = false`, `class: string = ""` +- Slots: `icon`, `default`, `footer` +- Events: None + +### FeatureIconCard + +Feature card with a prominent themed icon treatment. + +- Mount: `data-component="FeatureIconCard"` +- Props: `icon: string = "icon-[lucide--sparkles]"`, `iconSize: string = "md"`, `iconVariant: string = "soft"`, `title: string = "Feature"`, `description: string = ""`, `href: string = ""`, `actionLabel: string = "Explore"`, `badge: string = ""`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `align: string = "left"`, `hover: string = "lift"`, `class: string = ""` +- Slots: `default`, `footer` +- Events: None + +### Hero + +Reusable public-page hero with actions, trust items, badges, and visual slots. + +- Mount: `data-component="Hero"` +- Props: `eyebrow: string = ""`, `title: string = "Build something remarkable"`, `highlight: string = ""`, `description: string = ""`, `align: string = "left"`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `primaryLabel: string = ""`, `primaryHref: string = ""`, `primaryIcon: string = ""`, `secondaryLabel: string = ""`, `secondaryHref: string = ""`, `secondaryIcon: string = ""`, `tertiaryLabel: string = ""`, `tertiaryHref: string = ""`, `badges: string = []`, `trustItems: string = []`, `maxWidth: string = "xl"`, `class: string = ""` +- Slots: `eyebrow`, `actions`, `trust`, `default`, `visual`, `footer` +- Events: None + +### MarketingSectionHeader + +Marketing section heading with an optional linked action. + +- Mount: `data-component="MarketingSectionHeader"` +- Props: `id: string = ""`, `eyebrow: string = ""`, `title: string = ""`, `description: string = ""`, `align: string = "split"`, `size: string = "default"`, `color: string = "primary"`, `actionLabel: string = ""`, `actionHref: string = ""`, `actionIcon: string = ""`, `actionExternal: boolean = false`, `class: string = ""` +- Slots: `icon`, `actions`, `default` +- Events: None + +### MetricCard + +Single statistic or operational metric with icon, trend, and optional action. + +- Mount: `data-component="MetricCard"` +- Props: `label: string = "Metric"`, `value: string = "0"`, `description: string = ""`, `icon: string = ""`, `prefix: string = ""`, `suffix: string = ""`, `trend: string = ""`, `trendLabel: string = ""`, `trendDirection: string = "neutral"`, `href: string = ""`, `actionLabel: string = ""`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `align: string = "left"`, `class: string = ""` +- Slots: None +- Events: None + +### PageHeader + +Public and application page header with breadcrumbs, metadata, and actions. + +- Mount: `data-component="PageHeader"` +- Props: `eyebrow: string = ""`, `title: string = ""`, `description: string = ""`, `icon: string = ""`, `align: string = "left"`, `size: string = "default"`, `compact: boolean = false`, `showBreadcrumbs: boolean = false`, `breadcrumbs: string = []`, `primaryLabel: string = ""`, `primaryHref: string = ""`, `primaryIcon: string = ""`, `secondaryLabel: string = ""`, `secondaryHref: string = ""`, `secondaryIcon: string = ""`, `color: string = "primary"`, `variant: string = "default"`, `class: string = ""` +- Slots: `meta`, `actions`, `default` +- Events: None + ### PortalDashboard Responsive portal dashboard with metrics, actions, tasks, and updates. @@ -341,6 +422,24 @@ Responsive portal dashboard with metrics, actions, tasks, and updates. - Slots: `hero-action` - Events: `action`, `navigate` +### SplitHero + +Two-column hero with configurable content and visual placement. + +- Mount: `data-component="SplitHero"` +- Props: `eyebrow: string = ""`, `title: string = "A better digital experience"`, `highlight: string = ""`, `description: string = ""`, `primaryLabel: string = ""`, `primaryHref: string = ""`, `primaryIcon: string = ""`, `secondaryLabel: string = ""`, `secondaryHref: string = ""`, `secondaryIcon: string = ""`, `visualPosition: string = "right"`, `reverse: boolean = false`, `ratio: string = "balanced"`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `trustItems: string = []`, `class: string = ""` +- Slots: `actions`, `trust`, `default`, `visual` +- Events: None + +### StatsBar + +Compact responsive statistics strip. + +- Mount: `data-component="StatsBar"` +- Props: `items: string = []`, `columns: number = 4`, `compact: boolean = true`, `dividers: boolean = true`, `icons: boolean = true`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "raised"`, `maxWidth: string = "xl"`, `class: string = ""` +- Slots: None +- Events: None + ## Forms ### AuthForm @@ -541,7 +640,7 @@ Theme-aware, responsive map component. - Mount: `data-component="Map"` - Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Map"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` - Slots: `default` -- Events: `ready`, `move`, `zoom`, `markerClick` +- Events: None ### ToastNotifications @@ -608,6 +707,15 @@ Theme-aware, responsive divider component. - Slots: None - Events: None +### FeatureGrid + +Responsive equal-height grid for feature and service cards. + +- Mount: `data-component="FeatureGrid"` +- Props: `color: string = "primary"`, `size: string = "default"`, `columns: number = 3`, `tabletColumns: number = 2`, `mobileColumns: number = 1`, `gap: string = "md"`, `minItemWidth: string = ""`, `equalHeight: boolean = true`, `align: string = "stretch"`, `maxWidth: string = "full"`, `class: string = ""` +- Slots: `default` +- Events: None + ### Grid Theme-aware, responsive grid component. @@ -624,7 +732,7 @@ Theme-aware, responsive image component. - Mount: `data-component="Image"` - Props: `size: string = "default"`, `color: string = "primary"`, `src: string = ""`, `alt: string = ""`, `width: string = ""`, `height: string = ""`, `loading: string = "lazy"`, `rounded: boolean = false`, `class: string = ""` - Slots: `default` -- Events: `load`, `error` +- Events: None ### Kbd @@ -651,6 +759,51 @@ Theme-aware, responsive link component. - Mount: `data-component="Link"` - Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Link"`, `href: string = "#"`, `target: string = ""`, `rel: string = ""`, `external: boolean = false`, `class: string = ""` - Slots: `default` +- Events: None + +### MetricGrid + +Responsive collection of metric cards. + +- Mount: `data-component="MetricGrid"` +- Props: `items: string = []`, `columns: number = 4`, `tabletColumns: number = 2`, `mobileColumns: number = 1`, `gap: string = "md"`, `equalHeight: boolean = true`, `dividers: boolean = false`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: None + +### PublicPageShell + +Consistent structural wrapper for public-facing pages. + +- Mount: `data-component="PublicPageShell"` +- Props: `maxWidth: string = "full"`, `fullWidth: boolean = true`, `headerOffset: string = "none"`, `background: string = "default"`, `overflow: string = "clip"`, `minHeight: string = "screen"`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `class: string = ""` +- Slots: `before`, `default`, `after` +- Events: None + +### Section + +Theme-aware page section with consistent spacing, width, background, and border controls. + +- Mount: `data-component="Section"` +- Props: `id: string = ""`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `spacing: string = "lg"`, `maxWidth: string = "xl"`, `fullWidth: boolean = false`, `borderTop: boolean = false`, `borderBottom: boolean = false`, `class: string = ""` +- Slots: `default` +- Events: None + +### SectionHeader + +Reusable accessible section heading with eyebrow, title, description, icon, and actions. + +- Mount: `data-component="SectionHeader"` +- Props: `id: string = ""`, `eyebrow: string = ""`, `title: string = ""`, `description: string = ""`, `align: string = "left"`, `size: string = "default"`, `color: string = "primary"`, `headingLevel: number = 2`, `maxWidth: string = "3xl"`, `class: string = ""` +- Slots: `icon`, `default`, `actions` +- Events: None + +### TextLink + +Styled inline action link with icons, arrows, external state, and disabled handling. + +- Mount: `data-component="TextLink"` +- Props: `label: string = "Learn more"`, `href: string = "#"`, `target: string = ""`, `rel: string = ""`, `external: boolean = false`, `icon: string = ""`, `iconPosition: string = "start"`, `showArrow: boolean = true`, `underline: boolean = false`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `disabled: boolean = false`, `class: string = ""` +- Slots: None - Events: `click`, `focus`, `blur` ### Typography @@ -664,6 +817,15 @@ Theme-aware, responsive typography component. ## Navigation +### BackToTop + +Accessible scroll-to-top control with visibility threshold. + +- Mount: `data-component="BackToTop"` +- Props: `threshold: number = 500`, `label: string = "Back to top"`, `ariaLabel: string = "Scroll back to top"`, `icon: string = "icon-[lucide--arrow-up]"`, `position: string = "right"`, `offset: string = "md"`, `behavior: string = "smooth"`, `showProgress: boolean = false`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "solid"`, `class: string = ""` +- Slots: None +- Events: None + ### Breadcrumb Theme-aware, responsive breadcrumb component. @@ -679,7 +841,7 @@ Responsive application footer with structured links and pre/post content slots. - Mount: `data-component="Footer"` - Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Footer navigation"`, `items: string = []`, `columns: number = 3`, `maxWidth: string = "compact"`, `copyright: string = ""`, `class: string = ""` -- Slots: `pre-footer`, `post-footer`, `copyright-left`, `copyright-right` +- Slots: `pre-footer`, `copyright-left`, `copyright-right`, `post-footer` - Events: `select`, `action` ### MegaMenu @@ -761,7 +923,7 @@ Theme-aware, responsive tabs component. - Mount: `data-component="Tabs"` - Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Tabs"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""` - Slots: `default` -- Events: `change`, `select` +- Events: None ## Overlays diff --git a/.publish/ui/component-catalog.json b/.publish/ui/component-catalog.json index 1b3bfeb3..299cb70b 100644 --- a/.publish/ui/component-catalog.json +++ b/.publish/ui/component-catalog.json @@ -1,66 +1,47 @@ { "sourceDocuments": ["Screenshot-directed WRNexus UI catalog reset"], "components": [ - { - "name": "Container", - "category": "layout", - "purpose": "Theme-aware, responsive container component." - }, - { - "name": "Columns", - "category": "layout", - "purpose": "Theme-aware, responsive columns component." - }, - { - "name": "Grid", - "category": "layout", - "purpose": "Theme-aware, responsive grid component." - }, - { - "name": "LayoutSplitter", - "category": "layout", - "purpose": "Theme-aware, responsive layout splitter component." - }, - { - "name": "Typography", - "category": "layout", - "purpose": "Theme-aware, responsive typography component." - }, - { - "name": "Image", - "category": "layout", - "purpose": "Theme-aware, responsive image component." - }, - { - "name": "Link", - "category": "layout", - "purpose": "Theme-aware, responsive link component." - }, - { - "name": "Divider", - "category": "layout", - "purpose": "Theme-aware, responsive divider component." - }, - { - "name": "Kbd", - "category": "layout", - "purpose": "Theme-aware, responsive kbd component." - }, - { - "name": "CustomScrollbar", - "category": "layout", - "purpose": "Theme-aware, responsive custom scrollbar component." - }, { "name": "Accordion", "category": "base", "purpose": "Theme-aware, responsive accordion component." }, + { + "name": "AdvancedDatePicker", + "category": "integrations", + "purpose": "Theme-aware, responsive advanced date picker component." + }, + { + "name": "AdvancedRangeSlider", + "category": "integrations", + "purpose": "Theme-aware, responsive advanced range slider component." + }, + { + "name": "AdvancedSelect", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive advanced select component.", + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"] + }, { "name": "Alert", "category": "base", "purpose": "Theme-aware, responsive alert component." }, + { + "name": "AnnouncementBar", + "category": "blocks", + "purpose": "Accessible public announcement, emergency, maintenance, or status bar." + }, + { + "name": "AuthForm", + "category": "forms", + "purpose": "Reusable authentication form for sign-in, registration, recovery, reset, and MFA." + }, + { + "name": "AuthSplitLayout", + "category": "layout", + "purpose": "Responsive 50/50 authentication layout with content and form regions." + }, { "name": "Avatar", "category": "base", @@ -71,6 +52,11 @@ "category": "base", "purpose": "Theme-aware, responsive avatar group component." }, + { + "name": "BackToTop", + "category": "navigation", + "purpose": "Accessible scroll-to-top control with visibility threshold." + }, { "name": "Badge", "category": "base", @@ -81,6 +67,11 @@ "category": "base", "purpose": "Theme-aware, responsive blockquote component." }, + { + "name": "Breadcrumb", + "category": "navigation", + "purpose": "Theme-aware, responsive breadcrumb component." + }, { "name": "Button", "category": "base", @@ -96,165 +87,20 @@ "category": "base", "purpose": "Theme-aware, responsive card component." }, - { - "name": "ChatBubble", - "category": "base", - "purpose": "Theme-aware, responsive chat bubble component." - }, { "name": "Carousel", "category": "base", "purpose": "Theme-aware, responsive carousel component." }, { - "name": "Collapse", + "name": "Chart", + "category": "integrations", + "purpose": "Theme-aware, responsive chart component." + }, + { + "name": "ChatBubble", "category": "base", - "purpose": "Theme-aware, responsive collapse component." - }, - { - "name": "DatePicker", - "category": "base", - "purpose": "Theme-aware, responsive date picker component." - }, - { - "name": "DeviceFrame", - "category": "base", - "purpose": "Theme-aware, responsive device frame component." - }, - { - "name": "List", - "category": "base", - "purpose": "Theme-aware, responsive list component." - }, - { - "name": "ListGroup", - "category": "base", - "purpose": "Theme-aware, responsive list group component." - }, - { - "name": "LegendIndicator", - "category": "base", - "purpose": "Theme-aware, responsive legend indicator component." - }, - { - "name": "Progress", - "category": "base", - "purpose": "Theme-aware, responsive progress component." - }, - { - "name": "FileUploadProgress", - "category": "base", - "purpose": "Theme-aware, responsive file upload progress component." - }, - { - "name": "Rating", - "category": "base", - "purpose": "Theme-aware, responsive rating component." - }, - { - "name": "Skeleton", - "category": "base", - "purpose": "Theme-aware, responsive skeleton component." - }, - { - "name": "Spinner", - "category": "base", - "purpose": "Theme-aware, responsive spinner component." - }, - { - "name": "StyledIcon", - "category": "base", - "purpose": "Theme-aware, responsive styled icon component." - }, - { - "name": "Toast", - "category": "base", - "purpose": "Theme-aware, responsive toast component." - }, - { - "name": "Timeline", - "category": "base", - "purpose": "Theme-aware, responsive timeline component." - }, - { - "name": "TreeView", - "category": "base", - "purpose": "Theme-aware, responsive tree view component." - }, - { - "name": "Marquee", - "category": "base", - "purpose": "Theme-aware, responsive marquee component." - }, - { - "name": "Navbar", - "category": "navigation", - "purpose": "Theme-aware, responsive navbar component." - }, - { - "name": "Footer", - "category": "navigation", - "purpose": "Responsive application footer with structured links and pre/post content slots." - }, - { - "name": "MegaMenu", - "category": "navigation", - "purpose": "Theme-aware, responsive mega menu component." - }, - { - "name": "Nav", - "category": "navigation", - "purpose": "Theme-aware, responsive nav component." - }, - { - "name": "Tabs", - "category": "navigation", - "purpose": "Theme-aware, responsive tabs component." - }, - { - "name": "Sidebar", - "category": "navigation", - "purpose": "Theme-aware, responsive sidebar component." - }, - { - "name": "Scrollspy", - "category": "navigation", - "purpose": "Theme-aware, responsive scrollspy component." - }, - { - "name": "Breadcrumb", - "category": "navigation", - "purpose": "Theme-aware, responsive breadcrumb component." - }, - { - "name": "Pagination", - "category": "navigation", - "purpose": "Theme-aware, responsive pagination component." - }, - { - "name": "Stepper", - "category": "navigation", - "purpose": "Theme-aware, responsive stepper component." - }, - { - "name": "Input", - "category": "forms", - "purpose": "Theme-aware, responsive input component." - }, - { - "name": "InputGroup", - "category": "forms", - "purpose": "Theme-aware, responsive input group component." - }, - { - "name": "Textarea", - "category": "forms", - "purpose": "Theme-aware, responsive textarea component." - }, - { - "name": "FileInput", - "category": "forms", - "purpose": "Theme-aware, responsive file input component." + "purpose": "Theme-aware, responsive chat bubble component." }, { "name": "Checkbox", @@ -262,24 +108,14 @@ "purpose": "Theme-aware, responsive checkbox component." }, { - "name": "Radio", - "category": "forms", - "purpose": "Theme-aware, responsive radio component." + "name": "Clipboard", + "category": "integrations", + "purpose": "Theme-aware, responsive clipboard component." }, { - "name": "Switch", - "category": "forms", - "purpose": "Theme-aware, responsive switch component." - }, - { - "name": "Select", - "category": "forms", - "purpose": "Theme-aware, responsive select component." - }, - { - "name": "RangeSlider", - "category": "forms", - "purpose": "Theme-aware, responsive range slider component." + "name": "Collapse", + "category": "base", + "purpose": "Theme-aware, responsive collapse component." }, { "name": "ColorPicker", @@ -287,15 +123,9 @@ "purpose": "Theme-aware, responsive color picker component." }, { - "name": "TimePicker", - "category": "forms", - "purpose": "Theme-aware, responsive time picker component." - }, - { - "name": "AdvancedSelect", - "category": "advanced-forms", - "purpose": "Theme-aware, responsive advanced select component.", - "events": ["search", "select", "change", "clear", "open", "close", "load", "error"] + "name": "Columns", + "category": "layout", + "purpose": "Theme-aware, responsive columns component." }, { "name": "ComboBox", @@ -304,46 +134,14 @@ "events": ["search", "select", "change", "clear", "open", "close", "load", "error"] }, { - "name": "SearchBox", - "category": "advanced-forms", - "purpose": "Theme-aware, responsive search box component." + "name": "Confetti", + "category": "integrations", + "purpose": "Theme-aware, responsive confetti component." }, { - "name": "InputNumber", - "category": "advanced-forms", - "purpose": "Theme-aware, responsive input number component." - }, - { - "name": "StrongPassword", - "category": "advanced-forms", - "purpose": "Theme-aware, responsive strong password component." - }, - { - "name": "TogglePassword", - "category": "advanced-forms", - "purpose": "Accessible password field with optional show and hide controls.", - "events": ["input", "change", "toggle"] - }, - { - "name": "ToggleCount", - "category": "advanced-forms", - "purpose": "Theme-aware, responsive toggle count component." - }, - { - "name": "CopyMarkup", - "category": "advanced-forms", - "purpose": "Theme-aware, responsive copy markup component." - }, - { - "name": "PinInput", - "category": "advanced-forms", - "purpose": "Secure multi-cell PIN and verification-code input with regex and paste support.", - "events": ["input", "change", "complete", "paste", "clear", "error"] - }, - { - "name": "Dropdown", - "category": "overlays", - "purpose": "Theme-aware, responsive dropdown component." + "name": "Container", + "category": "layout", + "purpose": "Theme-aware, responsive container component." }, { "name": "ContextMenu", @@ -351,54 +149,19 @@ "purpose": "Theme-aware, responsive context menu component." }, { - "name": "Modal", - "category": "overlays", - "purpose": "Theme-aware, responsive modal component." + "name": "CopyMarkup", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive copy markup component." }, { - "name": "Drawer", - "category": "overlays", - "purpose": "Theme-aware, responsive drawer component." + "name": "CTASection", + "category": "blocks", + "purpose": "Reusable closing call-to-action section with primary and secondary actions." }, { - "name": "Popover", - "category": "overlays", - "purpose": "Theme-aware, responsive popover component." - }, - { - "name": "Tooltip", - "category": "overlays", - "purpose": "Theme-aware, responsive tooltip component." - }, - { - "name": "Table", - "category": "tables", - "purpose": "Theme-aware, responsive table component." - }, - { - "name": "AdvancedRangeSlider", - "category": "integrations", - "purpose": "Theme-aware, responsive advanced range slider component." - }, - { - "name": "AdvancedDatePicker", - "category": "integrations", - "purpose": "Theme-aware, responsive advanced date picker component." - }, - { - "name": "Chart", - "category": "integrations", - "purpose": "Theme-aware, responsive chart component." - }, - { - "name": "Clipboard", - "category": "integrations", - "purpose": "Theme-aware, responsive clipboard component." - }, - { - "name": "Confetti", - "category": "integrations", - "purpose": "Theme-aware, responsive confetti component." + "name": "CustomScrollbar", + "category": "layout", + "purpose": "Theme-aware, responsive custom scrollbar component." }, { "name": "DataMap", @@ -410,35 +173,201 @@ "category": "integrations", "purpose": "Theme-aware, responsive data table component." }, + { + "name": "DatePicker", + "category": "base", + "purpose": "Theme-aware, responsive date picker component." + }, + { + "name": "DeviceFrame", + "category": "base", + "purpose": "Theme-aware, responsive device frame component." + }, + { + "name": "Divider", + "category": "layout", + "purpose": "Theme-aware, responsive divider component." + }, { "name": "DragAndDrop", "category": "integrations", "purpose": "Theme-aware, responsive drag and drop component." }, + { + "name": "Drawer", + "category": "overlays", + "purpose": "Theme-aware, responsive drawer component." + }, + { + "name": "Dropdown", + "category": "overlays", + "purpose": "Theme-aware, responsive dropdown component." + }, + { + "name": "FeatureCard", + "category": "blocks", + "purpose": "Reusable linked feature or service card with icon, badge, description, and action." + }, + { + "name": "FeatureGrid", + "category": "layout", + "purpose": "Responsive equal-height grid for feature and service cards." + }, + { + "name": "FeatureIconCard", + "category": "blocks", + "purpose": "Feature card with a prominent themed icon treatment." + }, + { + "name": "FileInput", + "category": "forms", + "purpose": "Theme-aware, responsive file input component." + }, { "name": "FileUpload", "category": "integrations", "purpose": "Theme-aware, responsive file upload component." }, + { + "name": "FileUploadProgress", + "category": "base", + "purpose": "Theme-aware, responsive file upload progress component." + }, + { + "name": "Footer", + "category": "navigation", + "purpose": "Responsive application footer with structured links and pre/post content slots." + }, + { + "name": "Grid", + "category": "layout", + "purpose": "Theme-aware, responsive grid component." + }, + { + "name": "Hero", + "category": "blocks", + "purpose": "Reusable public-page hero with actions, trust items, badges, and visual slots." + }, + { + "name": "HeroActions", + "category": "base", + "purpose": "Responsive action group for hero and call-to-action sections." + }, + { + "name": "Image", + "category": "layout", + "purpose": "Theme-aware, responsive image component." + }, + { + "name": "Input", + "category": "forms", + "purpose": "Theme-aware, responsive input component." + }, + { + "name": "InputGroup", + "category": "forms", + "purpose": "Theme-aware, responsive input group component." + }, + { + "name": "InputNumber", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive input number component." + }, + { + "name": "Kbd", + "category": "layout", + "purpose": "Theme-aware, responsive kbd component." + }, + { + "name": "LayoutSplitter", + "category": "layout", + "purpose": "Theme-aware, responsive layout splitter component." + }, + { + "name": "LegendIndicator", + "category": "base", + "purpose": "Theme-aware, responsive legend indicator component." + }, + { + "name": "Link", + "category": "layout", + "purpose": "Theme-aware, responsive link component." + }, + { + "name": "List", + "category": "base", + "purpose": "Theme-aware, responsive list component." + }, + { + "name": "ListGroup", + "category": "base", + "purpose": "Theme-aware, responsive list group component." + }, { "name": "Map", "category": "integrations", "purpose": "Theme-aware, responsive map component." }, { - "name": "ToastNotifications", - "category": "integrations", - "purpose": "Theme-aware, responsive toast notifications component." + "name": "MarketingSectionHeader", + "category": "blocks", + "purpose": "Marketing section heading with an optional linked action." }, { - "name": "WysiwygEditor", - "category": "integrations", - "purpose": "Theme-aware, responsive wysiwyg editor component." + "name": "Marquee", + "category": "base", + "purpose": "Theme-aware, responsive marquee component." }, { - "name": "PreferenceSwitcher", + "name": "MegaMenu", "category": "navigation", - "purpose": "Accessible theme, accent color, and language preference controls." + "purpose": "Theme-aware, responsive mega menu component." + }, + { + "name": "MetricCard", + "category": "blocks", + "purpose": "Single statistic or operational metric with icon, trend, and optional action." + }, + { + "name": "MetricGrid", + "category": "layout", + "purpose": "Responsive collection of metric cards." + }, + { + "name": "Modal", + "category": "overlays", + "purpose": "Theme-aware, responsive modal component." + }, + { + "name": "Nav", + "category": "navigation", + "purpose": "Theme-aware, responsive nav component." + }, + { + "name": "Navbar", + "category": "navigation", + "purpose": "Theme-aware, responsive navbar component." + }, + { + "name": "PageHeader", + "category": "blocks", + "purpose": "Public and application page header with breadcrumbs, metadata, and actions." + }, + { + "name": "Pagination", + "category": "navigation", + "purpose": "Theme-aware, responsive pagination component." + }, + { + "name": "PinInput", + "category": "advanced-forms", + "purpose": "Secure multi-cell PIN and verification-code input with regex and paste support.", + "events": ["input", "change", "complete", "paste", "clear", "error"] + }, + { + "name": "Popover", + "category": "overlays", + "purpose": "Theme-aware, responsive popover component." }, { "name": "PortalDashboard", @@ -446,14 +375,175 @@ "purpose": "Responsive portal dashboard with metrics, actions, tasks, and updates." }, { - "name": "AuthSplitLayout", - "category": "layout", - "purpose": "Responsive 50/50 authentication layout with content and form regions." + "name": "PreferenceSwitcher", + "category": "navigation", + "purpose": "Accessible theme, accent color, and language preference controls." }, { - "name": "AuthForm", + "name": "Progress", + "category": "base", + "purpose": "Theme-aware, responsive progress component." + }, + { + "name": "PublicPageShell", + "category": "layout", + "purpose": "Consistent structural wrapper for public-facing pages." + }, + { + "name": "Radio", "category": "forms", - "purpose": "Reusable authentication form for sign-in, registration, recovery, reset, and MFA." + "purpose": "Theme-aware, responsive radio component." + }, + { + "name": "RangeSlider", + "category": "forms", + "purpose": "Theme-aware, responsive range slider component." + }, + { + "name": "Rating", + "category": "base", + "purpose": "Theme-aware, responsive rating component." + }, + { + "name": "Scrollspy", + "category": "navigation", + "purpose": "Theme-aware, responsive scrollspy component." + }, + { + "name": "SearchBox", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive search box component." + }, + { + "name": "Section", + "category": "layout", + "purpose": "Theme-aware page section with consistent spacing, width, background, and border controls." + }, + { + "name": "SectionHeader", + "category": "layout", + "purpose": "Reusable accessible section heading with eyebrow, title, description, icon, and actions." + }, + { + "name": "Select", + "category": "forms", + "purpose": "Theme-aware, responsive select component." + }, + { + "name": "Sidebar", + "category": "navigation", + "purpose": "Theme-aware, responsive sidebar component." + }, + { + "name": "Skeleton", + "category": "base", + "purpose": "Theme-aware, responsive skeleton component." + }, + { + "name": "Spinner", + "category": "base", + "purpose": "Theme-aware, responsive spinner component." + }, + { + "name": "SplitHero", + "category": "blocks", + "purpose": "Two-column hero with configurable content and visual placement." + }, + { + "name": "StatsBar", + "category": "blocks", + "purpose": "Compact responsive statistics strip." + }, + { + "name": "Stepper", + "category": "navigation", + "purpose": "Theme-aware, responsive stepper component." + }, + { + "name": "StrongPassword", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive strong password component." + }, + { + "name": "StyledIcon", + "category": "base", + "purpose": "Theme-aware, responsive styled icon component." + }, + { + "name": "Switch", + "category": "forms", + "purpose": "Theme-aware, responsive switch component." + }, + { + "name": "Table", + "category": "tables", + "purpose": "Theme-aware, responsive table component." + }, + { + "name": "Tabs", + "category": "navigation", + "purpose": "Theme-aware, responsive tabs component." + }, + { + "name": "Textarea", + "category": "forms", + "purpose": "Theme-aware, responsive textarea component." + }, + { + "name": "TextLink", + "category": "layout", + "purpose": "Styled inline action link with icons, arrows, external state, and disabled handling." + }, + { + "name": "Timeline", + "category": "base", + "purpose": "Theme-aware, responsive timeline component." + }, + { + "name": "TimePicker", + "category": "forms", + "purpose": "Theme-aware, responsive time picker component." + }, + { + "name": "Toast", + "category": "base", + "purpose": "Theme-aware, responsive toast component." + }, + { + "name": "ToastNotifications", + "category": "integrations", + "purpose": "Theme-aware, responsive toast notifications component." + }, + { + "name": "ToggleCount", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive toggle count component." + }, + { + "name": "TogglePassword", + "category": "advanced-forms", + "purpose": "Accessible password field with optional show and hide controls.", + "events": ["input", "change", "toggle"] + }, + { + "name": "Tooltip", + "category": "overlays", + "purpose": "Theme-aware, responsive tooltip component." + }, + { + "name": "TreeView", + "category": "base", + "purpose": "Theme-aware, responsive tree view component." + }, + { + "name": "Typography", + "category": "layout", + "purpose": "Theme-aware, responsive typography component." + }, + { + "name": "WysiwygEditor", + "category": "integrations", + "purpose": "Theme-aware, responsive wysiwyg editor component." } ] } diff --git a/.publish/ui/component-reference.json b/.publish/ui/component-reference.json index 5d977840..8a319957 100644 --- a/.publish/ui/component-reference.json +++ b/.publish/ui/component-reference.json @@ -1,6 +1,6 @@ { "generatedFrom": "packages/ui/components/*.wrn", - "count": 90, + "count": 108, "components": [ { "name": "Accordion", @@ -675,6 +675,125 @@ "events": ["dismiss", "action"], "source": "components/alert.wrn" }, + { + "name": "AnnouncementBar", + "mount": "AnnouncementBar", + "category": "blocks", + "purpose": "Accessible public announcement, emergency, maintenance, or status bar.", + "props": [ + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badgeIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "message", + "type": "string", + "required": false, + "default": "\"Announcement\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--megaphone]\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "dismissible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dismissLabel", + "type": "string", + "required": false, + "default": "\"Dismiss announcement\"" + }, + { + "name": "sticky", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"soft\"" + }, + { + "name": "role", + "type": "string", + "required": false, + "default": "\"status\"" + }, + { + "name": "live", + "type": "string", + "required": false, + "default": "\"polite\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/AnnouncementBar.wrn" + }, { "name": "AuthForm", "mount": "AuthForm", @@ -1025,6 +1144,89 @@ "events": ["overflow"], "source": "components/AvatarGroup.wrn" }, + { + "name": "BackToTop", + "mount": "BackToTop", + "category": "navigation", + "purpose": "Accessible scroll-to-top control with visibility threshold.", + "props": [ + { + "name": "threshold", + "type": "number", + "required": false, + "default": "500" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Back to top\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Scroll back to top\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--arrow-up]\"" + }, + { + "name": "position", + "type": "string", + "required": false, + "default": "\"right\"" + }, + { + "name": "offset", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "behavior", + "type": "string", + "required": false, + "default": "\"smooth\"" + }, + { + "name": "showProgress", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/BackToTop.wrn" + }, { "name": "Badge", "mount": "Badge", @@ -1755,7 +1957,7 @@ ], "slots": ["default"], "events": ["click", "action", "navigate", "dismiss", "load", "error"], - "source": "components/card.wrn" + "source": "components/Card.wrn" }, { "name": "Carousel", @@ -2853,7 +3055,7 @@ ], "slots": ["default"], "events": [], - "source": "components/container.wrn" + "source": "components/Container.wrn" }, { "name": "ContextMenu", @@ -3003,6 +3205,119 @@ "events": ["copy", "success", "error"], "source": "components/CopyMarkup.wrn" }, + { + "name": "CTASection", + "mount": "CTASection", + "category": "blocks", + "purpose": "Reusable closing call-to-action section with primary and secondary actions.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Ready to get started?\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"center\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"Get started\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"#\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "backgroundImage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default", "actions", "visual", "footer"], + "events": [], + "source": "components/CTASection.wrn" + }, { "name": "CustomScrollbar", "mount": "CustomScrollbar", @@ -3451,7 +3766,7 @@ ], "slots": [], "events": [], - "source": "components/divider.wrn" + "source": "components/Divider.wrn" }, { "name": "DragAndDrop", @@ -3612,6 +3927,279 @@ "events": ["toggle", "open", "close", "select"], "source": "components/Dropdown.wrn" }, + { + "name": "FeatureCard", + "mount": "FeatureCard", + "category": "blocks", + "purpose": "Reusable linked feature or service card with icon, badge, description, and action.", + "props": [ + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Feature\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"Learn more\"" + }, + { + "name": "actionIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badgeColor", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "hover", + "type": "string", + "required": false, + "default": "\"lift\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["icon", "default", "footer"], + "events": [], + "source": "components/FeatureCard.wrn" + }, + { + "name": "FeatureGrid", + "mount": "FeatureGrid", + "category": "layout", + "purpose": "Responsive equal-height grid for feature and service cards.", + "props": [ + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "tabletColumns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "mobileColumns", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "minItemWidth", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "equalHeight", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"stretch\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"full\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/FeatureGrid.wrn" + }, + { + "name": "FeatureIconCard", + "mount": "FeatureIconCard", + "category": "blocks", + "purpose": "Feature card with a prominent themed icon treatment.", + "props": [ + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--sparkles]\"" + }, + { + "name": "iconSize", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "iconVariant", + "type": "string", + "required": false, + "default": "\"soft\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Feature\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"Explore\"" + }, + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "hover", + "type": "string", + "required": false, + "default": "\"lift\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default", "footer"], + "events": [], + "source": "components/FeatureIconCard.wrn" + }, { "name": "FileInput", "mount": "FileInput", @@ -3946,7 +4534,7 @@ "default": "\"\"" } ], - "slots": ["pre-footer", "post-footer", "copyright-left", "copyright-right"], + "slots": ["pre-footer", "copyright-left", "copyright-right", "post-footer"], "events": ["select", "action"], "source": "components/Footer.wrn" }, @@ -3995,7 +4583,197 @@ ], "slots": ["default"], "events": [], - "source": "components/grid.wrn" + "source": "components/Grid.wrn" + }, + { + "name": "Hero", + "mount": "Hero", + "category": "blocks", + "purpose": "Reusable public-page hero with actions, trust items, badges, and visual slots.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Build something remarkable\"" + }, + { + "name": "highlight", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "tertiaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "tertiaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badges", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "trustItems", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["eyebrow", "actions", "trust", "default", "visual", "footer"], + "events": [], + "source": "components/Hero.wrn" + }, + { + "name": "HeroActions", + "mount": "HeroActions", + "category": "base", + "purpose": "Responsive action group for hero and call-to-action sections.", + "props": [ + { + "name": "actions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "stackOnMobile", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fullWidthMobile", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/HeroActions.wrn" }, { "name": "Image", @@ -4059,7 +4837,7 @@ } ], "slots": ["default"], - "events": ["load", "error"], + "events": [], "source": "components/Image.wrn" }, { @@ -4832,7 +5610,7 @@ } ], "slots": ["default"], - "events": ["click", "focus", "blur"], + "events": [], "source": "components/Link.wrn" }, { @@ -4885,7 +5663,7 @@ } ], "slots": ["default"], - "events": ["select", "click"], + "events": [], "source": "components/List.wrn" }, { @@ -4991,9 +5769,92 @@ } ], "slots": ["default"], - "events": ["ready", "move", "zoom", "markerClick"], + "events": [], "source": "components/Map.wrn" }, + { + "name": "MarketingSectionHeader", + "mount": "MarketingSectionHeader", + "category": "blocks", + "purpose": "Marketing section heading with an optional linked action.", + "props": [ + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"split\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionExternal", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["icon", "actions", "default"], + "events": [], + "source": "components/MarketingSectionHeader.wrn" + }, { "name": "Marquee", "mount": "Marquee", @@ -5044,7 +5905,7 @@ } ], "slots": ["default"], - "events": ["pause", "resume"], + "events": [], "source": "components/Marquee.wrn" }, { @@ -5100,6 +5961,190 @@ "events": ["open", "close", "select"], "source": "components/MegaMenu.wrn" }, + { + "name": "MetricCard", + "mount": "MetricCard", + "category": "blocks", + "purpose": "Single statistic or operational metric with icon, trend, and optional action.", + "props": [ + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Metric\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"0\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "prefix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "suffix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "trend", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "trendLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "trendDirection", + "type": "string", + "required": false, + "default": "\"neutral\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/MetricCard.wrn" + }, + { + "name": "MetricGrid", + "mount": "MetricGrid", + "category": "layout", + "purpose": "Responsive collection of metric cards.", + "props": [ + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "4" + }, + { + "name": "tabletColumns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "mobileColumns", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "equalHeight", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "dividers", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/MetricGrid.wrn" + }, { "name": "Modal", "mount": "Modal", @@ -5301,6 +6346,125 @@ "events": ["toggle", "open", "close", "select", "action"], "source": "components/Navbar.wrn" }, + { + "name": "PageHeader", + "mount": "PageHeader", + "category": "blocks", + "purpose": "Public and application page header with breadcrumbs, metadata, and actions.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showBreadcrumbs", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "breadcrumbs", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["meta", "actions", "default"], + "events": [], + "source": "components/PageHeader.wrn" + }, { "name": "Pagination", "mount": "Pagination", @@ -5793,6 +6957,77 @@ "events": [], "source": "components/progress.wrn" }, + { + "name": "PublicPageShell", + "mount": "PublicPageShell", + "category": "layout", + "purpose": "Consistent structural wrapper for public-facing pages.", + "props": [ + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"full\"" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "headerOffset", + "type": "string", + "required": false, + "default": "\"none\"" + }, + { + "name": "background", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "overflow", + "type": "string", + "required": false, + "default": "\"clip\"" + }, + { + "name": "minHeight", + "type": "string", + "required": false, + "default": "\"screen\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["before", "default", "after"], + "events": [], + "source": "components/PublicPageShell.wrn" + }, { "name": "Radio", "mount": "Radio", @@ -6313,9 +7548,151 @@ } ], "slots": [], - "events": ["input", "change", "search", "submit", "clear"], + "events": [], "source": "components/SearchBox.wrn" }, + { + "name": "Section", + "mount": "Section", + "category": "layout", + "purpose": "Theme-aware page section with consistent spacing, width, background, and border controls.", + "props": [ + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "spacing", + "type": "string", + "required": false, + "default": "\"lg\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "borderTop", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "borderBottom", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Section.wrn" + }, + { + "name": "SectionHeader", + "mount": "SectionHeader", + "category": "layout", + "purpose": "Reusable accessible section heading with eyebrow, title, description, icon, and actions.", + "props": [ + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "headingLevel", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"3xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["icon", "default", "actions"], + "events": [], + "source": "components/SectionHeader.wrn" + }, { "name": "Select", "mount": "Select", @@ -6600,6 +7977,196 @@ "events": [], "source": "components/spinner.wrn" }, + { + "name": "SplitHero", + "mount": "SplitHero", + "category": "blocks", + "purpose": "Two-column hero with configurable content and visual placement.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"A better digital experience\"" + }, + { + "name": "highlight", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "visualPosition", + "type": "string", + "required": false, + "default": "\"right\"" + }, + { + "name": "reverse", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "ratio", + "type": "string", + "required": false, + "default": "\"balanced\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "trustItems", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["actions", "trust", "default", "visual"], + "events": [], + "source": "components/SplitHero.wrn" + }, + { + "name": "StatsBar", + "mount": "StatsBar", + "category": "blocks", + "purpose": "Compact responsive statistics strip.", + "props": [ + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "4" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "dividers", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "icons", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"raised\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/StatsBar.wrn" + }, { "name": "Stepper", "mount": "Stepper", @@ -7113,7 +8680,7 @@ } ], "slots": ["default"], - "events": ["change", "select"], + "events": [], "source": "components/Tabs.wrn" }, { @@ -7265,6 +8832,101 @@ "events": ["input", "change", "focus", "blur", "invalid"], "source": "components/Textarea.wrn" }, + { + "name": "TextLink", + "mount": "TextLink", + "category": "layout", + "purpose": "Styled inline action link with icons, arrows, external state, and disabled handling.", + "props": [ + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Learn more\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"#\"" + }, + { + "name": "target", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "rel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "external", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "showArrow", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "underline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["click", "focus", "blur"], + "source": "components/TextLink.wrn" + }, { "name": "Timeline", "mount": "Timeline", @@ -7315,7 +8977,7 @@ } ], "slots": ["default"], - "events": ["select"], + "events": [], "source": "components/Timeline.wrn" }, { diff --git a/.publish/ui/components/Columns.wrn b/.publish/ui/components/Columns.wrn index a54a056e..96ac7ad1 100644 --- a/.publish/ui/components/Columns.wrn +++ b/.publish/ui/components/Columns.wrn @@ -7,7 +7,29 @@ component Columns { maxWidth = "xl" class = "" } + view { -
+
+ +
} } diff --git a/.publish/ui/components/Image.wrn b/.publish/ui/components/Image.wrn index 9d563ff9..881d5229 100644 --- a/.publish/ui/components/Image.wrn +++ b/.publish/ui/components/Image.wrn @@ -1,7 +1,5 @@ component Image { props { - @event load = function - @event error = function size = "default" color = "primary" src = "" @@ -12,10 +10,38 @@ component Image { rounded = false class = "" } + view { -
- {alt} - +
+ {#if src} + {alt} + {:else} + + {/if} + +
} } diff --git a/.publish/ui/components/Link.wrn b/.publish/ui/components/Link.wrn index a40cd330..3cf17764 100644 --- a/.publish/ui/components/Link.wrn +++ b/.publish/ui/components/Link.wrn @@ -1,8 +1,5 @@ component Link { props { - @event click = function - @event focus = function - @event blur = function size = "default" color = "primary" label = "Link" @@ -12,7 +9,39 @@ component Link { external = false class = "" } + view { - {label}{#if external}{/if} + + {label} + + {#if external} + + {/if} + + + } } diff --git a/.publish/ui/components/List.wrn b/.publish/ui/components/List.wrn index 27941140..0ac667a7 100644 --- a/.publish/ui/components/List.wrn +++ b/.publish/ui/components/List.wrn @@ -1,7 +1,5 @@ component List { props { - @event select = function - @event click = function size = "default" color = "primary" title = "List" @@ -10,12 +8,100 @@ component List { variant = "default" class = "" } + view { -
- {#if title}{title}{/if} - {#if description}

{description}

{/if} - {#if items}
{#each items as item}{item.label}{/each}
{/if} - +
+ {#if title || description} +
+ {#if title} +

{title}

+ {/if} + {#if description} +

{description}

+ {/if} +
+ {/if} + + + +
} } diff --git a/.publish/ui/components/Map.wrn b/.publish/ui/components/Map.wrn index f0037c76..6d0da585 100644 --- a/.publish/ui/components/Map.wrn +++ b/.publish/ui/components/Map.wrn @@ -1,9 +1,5 @@ component Map { props { - @event ready = function - @event move = function - @event zoom = function - @event markerClick = function size = "default" color = "primary" title = "Map" @@ -12,12 +8,78 @@ component Map { variant = "default" class = "" } + view { -
- {#if title}{title}{/if} - {#if description}

{description}

{/if} - {#if items}
{#each items as item}{item.label}{/each}
{/if} - +
+ {#if title || description} +
+
+ {#if title} +

{title}

+ {/if} + {#if description} +

{description}

+ {/if} +
+ + + +
+ {/if} + +
+ + +
+ +
+ + {#if items.length > 0} + {#each items as item, index} + + {/each} + {/if} + +
+ + +
+
} } diff --git a/.publish/ui/components/Marquee.wrn b/.publish/ui/components/Marquee.wrn index f0b772dd..53d4ca7b 100644 --- a/.publish/ui/components/Marquee.wrn +++ b/.publish/ui/components/Marquee.wrn @@ -1,7 +1,5 @@ component Marquee { props { - @event pause = function - @event resume = function size = "default" color = "primary" title = "Marquee" @@ -10,12 +8,104 @@ component Marquee { variant = "default" class = "" } + + state paused = false + view { -
- {#if title}{title}{/if} - {#if description}

{description}

{/if} - {#if items}
{#each items as item}{item.label}{/each}
{/if} - +
+
+ {#if title} +
+ + {title} +
+ {/if} + +
+
+ {#each items as item} + + + {item.label || item.title} + {#if item.meta} + {item.meta} + {/if} + + {:empty} +

{description || "No announcements available."}

+ {/each} + + {#if items.length > 0} + {#each items as item} + + {/each} + {/if} +
+
+ + +
+ +
} + + style { + .wire-marquee-track { + animation: wire-marquee 32s linear infinite; + } + + .wire-marquee-paused { + animation-play-state: paused; + } + + @keyframes wire-marquee { + from { transform: translateX(0); } + to { transform: translateX(-50%); } + } + + @media (prefers-reduced-motion: reduce) { + .wire-marquee-track { + animation: none; + } + } + } } diff --git a/.publish/ui/components/SearchBox.wrn b/.publish/ui/components/SearchBox.wrn index 941e22f3..bcb7243a 100644 --- a/.publish/ui/components/SearchBox.wrn +++ b/.publish/ui/components/SearchBox.wrn @@ -1,10 +1,5 @@ component SearchBox { props { - @event input = function - @event change = function - @event search = function - @event submit = function - @event clear = function size = "default" color = "primary" label = "Search Box" @@ -19,7 +14,67 @@ component SearchBox { required = false class = "" } + + state query = value + view { - + } } diff --git a/.publish/ui/components/Tabs.wrn b/.publish/ui/components/Tabs.wrn index a9270a70..e8d747c4 100644 --- a/.publish/ui/components/Tabs.wrn +++ b/.publish/ui/components/Tabs.wrn @@ -1,7 +1,5 @@ component Tabs { props { - @event change = function - @event select = function size = "default" color = "primary" label = "Tabs" @@ -10,10 +8,83 @@ component Tabs { orientation = "horizontal" class = "" } + + state activeValue = active || (items[0] ? (items[0].value || items[0].id || "0") : "") + view { - +
+
+ {#each items as item, index} + + {/each} +
+ +
+ {#each items as item, index} +
+ {#if item.title && item.title !== item.label} +

{item.title}

+ {/if} + {#if item.description} +

{item.description}

+ {/if} + {#if item.content} +
{item.content}
+ {/if} +
+ {/each} + + +
+
} } diff --git a/.publish/ui/components/Timeline.wrn b/.publish/ui/components/Timeline.wrn index ccf30f46..3d3d35dd 100644 --- a/.publish/ui/components/Timeline.wrn +++ b/.publish/ui/components/Timeline.wrn @@ -1,6 +1,5 @@ component Timeline { props { - @event select = function size = "default" color = "primary" title = "Timeline" @@ -9,12 +8,76 @@ component Timeline { variant = "default" class = "" } + view { -
- {#if title}{title}{/if} - {#if description}

{description}

{/if} - {#if items}
{#each items as item}{item.label}{/each}
{/if} - +
+ {#if title || description} +
+ {#if title} +

{title}

+ {/if} + {#if description} +

{description}

+ {/if} +
+ {/if} + +
    + {#each items as item, index} +
  1. + + + + +
    +
    +
    +

    {item.title || item.label}

    + {#if item.subtitle} +

    {item.subtitle}

    + {/if} +
    + {#if item.date || item.meta} + + {/if} +
    + + {#if item.description} +

    {item.description}

    + {/if} + + {#if item.href} + + {item.actionLabel || "View details"} + + + {/if} +
    +
  2. + {:empty} +
  3. No timeline items available.
  4. + {/each} +
+ +
} } diff --git a/.publish/ui/components/Typography.wrn b/.publish/ui/components/Typography.wrn index 0fecb460..d7d36173 100644 --- a/.publish/ui/components/Typography.wrn +++ b/.publish/ui/components/Typography.wrn @@ -7,7 +7,69 @@ component Typography { maxWidth = "xl" class = "" } + view { -
+
+ +
+ } + + style { + .wire-typography :where(h1, h2, h3, h4) { + color: var(--wire-color-text); + font-weight: 700; + letter-spacing: -0.02em; + line-height: 1.2; + break-after: avoid; + } + + .wire-typography :where(h1) { font-size: clamp(2rem, 4vw, 3.5rem); margin: 0 0 1.5rem; } + .wire-typography :where(h2) { font-size: clamp(1.5rem, 3vw, 2.25rem); margin: 2.5rem 0 1rem; } + .wire-typography :where(h3) { font-size: 1.35rem; margin: 2rem 0 0.75rem; } + .wire-typography :where(p, ul, ol, blockquote, pre, table) { margin: 1rem 0; } + .wire-typography :where(p, li) { color: var(--wire-color-text-muted); line-height: 1.8; } + .wire-typography :where(a) { color: var(--wire-color-primary); font-weight: 600; text-underline-offset: 0.2em; } + .wire-typography :where(a:hover) { color: var(--wire-color-primary-hover); text-decoration: underline; } + .wire-typography :where(ul, ol) { padding-left: 1.4rem; } + .wire-typography :where(ul) { list-style: disc; } + .wire-typography :where(ol) { list-style: decimal; } + .wire-typography :where(blockquote) { + border-left: 4px solid var(--wire-color-primary); + background: var(--wire-color-primary-soft); + border-radius: 0 0.75rem 0.75rem 0; + padding: 1rem 1.25rem; + color: var(--wire-color-text); + } + .wire-typography :where(code) { + border-radius: 0.35rem; + background: var(--wire-color-surface-soft); + padding: 0.15rem 0.35rem; + font-size: 0.9em; + } + .wire-typography :where(pre) { + overflow-x: auto; + border: 1px solid var(--wire-color-border); + border-radius: 1rem; + background: var(--wire-color-surface-raised); + padding: 1rem; + } + .wire-typography :where(img) { border-radius: 1rem; } + .wire-typography :where(hr) { border-color: var(--wire-color-border); margin: 2rem 0; } } } diff --git a/.publish/ui/components/card.wrn b/.publish/ui/components/card.wrn index 1948c5b0..e0239b9b 100644 --- a/.publish/ui/components/card.wrn +++ b/.publish/ui/components/card.wrn @@ -39,221 +39,311 @@ component Card { class = "" } - state visible = true - state selectedNav = activeNav + state dismissed = false functions { - function chooseNavigation(item, index) { - previousValue = selectedNav - selectedNav = item.value || item.label - $emit("navigate", { - value: selectedNav, - previousValue: previousValue, + function dispatchCardNavigation(sourceEvent, item, index, root, customEvent) { + root = sourceEvent.currentTarget.closest("[data-wrn-card]") + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("navigate", true, false, { + component: "Card", item: item, index: index }) + root.dispatchEvent(customEvent) } - function chooseMobileNavigation(sourceEvent) { - previousValue = selectedNav - selectedNav = sourceEvent.target.value - $emit("navigate", { - value: selectedNav, - previousValue: previousValue + function dispatchCardNavigationValue(sourceEvent, root, customEvent) { + root = sourceEvent.currentTarget.closest("[data-wrn-card]") + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("navigate", true, false, { + component: "Card", + value: sourceEvent.currentTarget.value }) + root.dispatchEvent(customEvent) } - function chooseAction(action, index) { - $emit("action", { + function dispatchCardHeaderAction(sourceEvent, action, index, root, customEvent) { + root = sourceEvent.currentTarget.closest("[data-wrn-card]") + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("action", true, false, { + component: "Card", action: action, index: index }) + root.dispatchEvent(customEvent) } - function dismissCard(sourceEvent) { - panel = sourceEvent.currentTarget.closest(".wire-next__card-panel") - if (panel) { - panel.setAttribute("hidden", "") + function dismissCard(sourceEvent, root, customEvent) { + dismissed = true + root = sourceEvent.currentTarget.closest("[data-wrn-card]") + + if (!root) { + return } - visible = false - $emit("dismiss", { + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("dismiss", true, false, { + component: "Card", title: title }) + root.dispatchEvent(customEvent) } } view { -
{#if items.length > 0}
- {#each items as item} -
- {#if item.imageSrc} + {#each items as item, itemIndex} +
+ {#if item.imageSrc || item.image}
- {item.imageAlt || ''} + {item.imageAlt || item.alt || ""}
{/if} -
- {#if item.title}

{item.title}

{/if} - {#if item.description}

{item.description}

{/if} + +
+ {#if item.title || item.label} +

{item.title || item.label}

+ {/if} + {#if item.subtitle} +

{item.subtitle}

+ {/if} + {#if item.description} +

{item.description}

+ {/if} + {#if item.actionLabel || item.href} + + {item.actionLabel || "Learn more"} + + + {/if}
- {#if item.footer}
{item.footer}
{/if}
{/each}
- {:else if visible} -
- {#if imagePosition === "overlay" && imageSrc} -
+ {:else} + {/if} -
+ } } diff --git a/.publish/ui/components/container.wrn b/.publish/ui/components/container.wrn index 84d7b0a9..bcc3a50f 100644 --- a/.publish/ui/components/container.wrn +++ b/.publish/ui/components/container.wrn @@ -7,7 +7,40 @@ component Container { maxWidth = "xl" class = "" } + view { -
+
+ +
} } diff --git a/.publish/ui/components/divider.wrn b/.publish/ui/components/divider.wrn index a724621f..b7a19a9f 100644 --- a/.publish/ui/components/divider.wrn +++ b/.publish/ui/components/divider.wrn @@ -6,7 +6,64 @@ component Divider { orientation = "horizontal" class = "" } + view { - +
+ {#if orientation === "vertical"} + + {:else} + + {/if} +
} } diff --git a/.publish/ui/components/grid.wrn b/.publish/ui/components/grid.wrn index 1cee0963..b76a5447 100644 --- a/.publish/ui/components/grid.wrn +++ b/.publish/ui/components/grid.wrn @@ -7,7 +7,34 @@ component Grid { maxWidth = "xl" class = "" } + view { -
+
+ +
} } diff --git a/.publish/ui/package.json b/.publish/ui/package.json index da46abcd..701dc069 100644 --- a/.publish/ui/package.json +++ b/.publish/ui/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/ui", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/ui — part of the WrNexus framework.", "license": "MIT", @@ -26,7 +26,7 @@ "./ui.css": "./ui.css" }, "dependencies": { - "@wrnexus/core": "^0.5.11" + "@wrnexus/core": "^0.5.12" }, "files": [ "dist", diff --git a/.publish/uploader/package.json b/.publish/uploader/package.json index b34477a8..497cb9b0 100644 --- a/.publish/uploader/package.json +++ b/.publish/uploader/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/uploader", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/uploader — part of the WrNexus framework.", "license": "MIT", @@ -21,7 +21,7 @@ } }, "dependencies": { - "@wrnexus/core": "^0.5.11" + "@wrnexus/core": "^0.5.12" }, "files": [ "dist" diff --git a/.publish/validation/package.json b/.publish/validation/package.json index 55b5b329..fe4fc651 100644 --- a/.publish/validation/package.json +++ b/.publish/validation/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/validation", - "version": "0.5.11", + "version": "0.5.12", "type": "module", "description": "@wrnexus/validation — part of the WrNexus framework.", "license": "MIT", diff --git a/.wrnexus-backups/ui-card-event-fix-2026-07-30T13-25-51-608Z/Card.wrn b/.wrnexus-backups/ui-card-event-fix-2026-07-30T13-25-51-608Z/Card.wrn new file mode 100644 index 00000000..d20d2e48 --- /dev/null +++ b/.wrnexus-backups/ui-card-event-fix-2026-07-30T13-25-51-608Z/Card.wrn @@ -0,0 +1,284 @@ +component Card { + props { + @event click = function + @event action = function + @event navigate = function + @event dismiss = function + @event load = function + @event error = function + title = "Card title" + subtitle = "" + description = "" + header = "" + footer = "" + imageSrc = "" + imageAlt = "" + imagePosition = "top" + actionLabel = "" + actionHref = "" + headerActions = [] + navigation = [] + activeNav = "" + mobileNavigation = false + alertTitle = "" + alertDescription = "" + empty = false + emptyTitle = "No data to show" + emptyIcon = "icon-[lucide--inbox]" + items = [] + size = "md" + color = "primary" + variant = "default" + layout = "vertical" + align = "left" + hover = "none" + scrollable = false + maxHeight = "18rem" + dismissible = false + ariaLabel = "" + class = "" + } + + state dismissed = false + + view { +
+ {#if items.length > 0} +
+ {#each items as item, itemIndex} + + {/each} +
+ {:else} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-card-final-fix-2026-07-30T13-11-39-927Z/Card.wrn b/.wrnexus-backups/ui-card-final-fix-2026-07-30T13-11-39-927Z/Card.wrn new file mode 100644 index 00000000..1567781c --- /dev/null +++ b/.wrnexus-backups/ui-card-final-fix-2026-07-30T13-11-39-927Z/Card.wrn @@ -0,0 +1,284 @@ +component Card { + props { + @event click = function + @event action = function + @event navigate = function + @event dismiss = function + @event load = function + @event error = function + title = "Card title" + subtitle = "" + description = "" + header = "" + footer = "" + imageSrc = "" + imageAlt = "" + imagePosition = "top" + actionLabel = "" + actionHref = "" + headerActions = [] + navigation = [] + activeNav = "" + mobileNavigation = false + alertTitle = "" + alertDescription = "" + empty = false + emptyTitle = "No data to show" + emptyIcon = "icon-[lucide--inbox]" + items = [] + size = "md" + color = "primary" + variant = "default" + layout = "vertical" + align = "left" + hover = "none" + scrollable = false + maxHeight = "18rem" + dismissible = false + ariaLabel = "" + class = "" + } + + state dismissed = false + + view { +
+ {#if items.length > 0} +
+ {#each items as item, itemIndex} + + {/each} +
+ {:else} +
+ {#if imageSrc && imagePosition === "overlay"} +
+ {imageAlt} + +
+ {/if} + + {#if imageSrc && (imagePosition === "top" || imagePosition === "left")} +
+ {imageAlt} +
+ {/if} + +
+ {#if header || title || subtitle || headerActions.length > 0 || dismissible} +
+
+ {#if header} +

{header}

+ {/if} + {#if title} +

{title}

+ {/if} + {#if subtitle} +

{subtitle}

+ {/if} +
+ + {#if headerActions.length > 0 || dismissible} +
+ {#each headerActions as headerAction, actionIndex} + + {/each} + + {#if dismissible} + + {/if} +
+ {/if} +
+ {/if} + + {#if navigation.length > 0} + + {/if} + + {#if alertTitle || alertDescription} +
+ {#if alertTitle} + {alertTitle} + {/if} + {#if alertDescription} +

{alertDescription}

+ {/if} +
+ {/if} + +
+ {#if empty} +
+ +

{emptyTitle}

+
+ {:else} + {#if description} +

{description}

+ {/if} + + {/if} +
+ + {#if footer || actionLabel} + + {/if} +
+ + {#if imageSrc && (imagePosition === "bottom" || imagePosition === "right")} +
+ {imageAlt} +
+ {/if} +
+ {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Accordion.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Accordion.wrn new file mode 100644 index 00000000..8e75cc66 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Accordion.wrn @@ -0,0 +1,203 @@ +component Accordion { + props { + size = "default" + color = "primary" + variant = "default" + class = "" + + id = "accordion" + items = [] + defaultOpen = [] + multiple = false + alwaysOpen = false + disabled = false + + indicator = "plus" + indicatorPosition = "start" + showIndicator = true + bordered = false + separated = false + flush = false + contentItalic = false + + @event change = function + @event open = function + @event close = function + } + + state openValues = defaultOpen + + functions { + function itemValue(item, index) { + return item.value !== undefined && item.value !== "" + ? String(item.value) + : String(index) + } + + function nestedValue(parent, parentIndex, item, index) { + return itemValue(parent, parentIndex) + "." + itemValue(item, index) + } + + function isOpen(value) { + return openValues.includes(value) + } + + function allowsMultiple() { + return multiple || alwaysOpen + } + + function dispatchAccordionEvent(sourceEvent, eventName, value, item, root, customEvent) { + root = sourceEvent.currentTarget.closest("[data-wrn-accordion]") + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent(eventName, true, false, { + component: "Accordion", + value: value, + item: item, + open: isOpen(value), + openValues: openValues + }) + root.dispatchEvent(customEvent) + } + + function toggleItem(sourceEvent, value, item, wasOpen) { + if (disabled || item.disabled) { + return + } + + wasOpen = isOpen(value) + + if (wasOpen) { + openValues = openValues.filter((entry) => entry !== value) + } else if (allowsMultiple()) { + openValues = openValues.concat([value]) + } else { + openValues = [value] + } + + dispatchAccordionEvent( + sourceEvent, + wasOpen ? "close" : "open", + value, + item + ) + dispatchAccordionEvent(sourceEvent, "change", value, item) + } + + } + + view { +
+ {#each items as item, index} +
+

+ +

+ +
+
+
+ {#if item.content}

{item.content}

{/if} + + {#if item.children && item.children.length > 0} +
+ {#each item.children as child, childIndex} +
+

+ +

+
+
+
+

{child.content}

+
+
+
+
+ {/each} +
+ {/if} +
+
+
+
+ {/each} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AdvancedDatePicker.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AdvancedDatePicker.wrn new file mode 100644 index 00000000..e9664362 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AdvancedDatePicker.wrn @@ -0,0 +1,24 @@ +component AdvancedDatePicker { + props { + @event input = function + @event change = function + @event open = function + @event close = function + @event clear = function + size = "default" + color = "primary" + title = "Advanced Date Picker" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AdvancedRangeSlider.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AdvancedRangeSlider.wrn new file mode 100644 index 00000000..51090087 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AdvancedRangeSlider.wrn @@ -0,0 +1,23 @@ +component AdvancedRangeSlider { + props { + @event input = function + @event change = function + @event start = function + @event end = function + size = "default" + color = "primary" + title = "Advanced Range Slider" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AdvancedSelect.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AdvancedSelect.wrn new file mode 100644 index 00000000..6bd6fe16 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AdvancedSelect.wrn @@ -0,0 +1,456 @@ +component AdvancedSelect { + props { + size = "default" + color = "primary" + label = "Advanced Select" + name = "" + value = "" + values = [] + options = [] + groups = [] + placeholder = "Select an option" + placeholderIcon = "" + searchPlaceholder = "Search options…" + multiple = false + searchable = true + defaultOpen = false + clearable = true + allowEmpty = true + tags = false + disabled = false + required = false + invalid = false + validationMessage = "" + helpText = "" + loading = false + loadingLabel = "Loading options…" + emptyLabel = "No options found" + selectedOptionsLabel = "Selected options" + clearLabel = "Clear selection" + createLabel = "Create" + loadMoreLabel = "Load more" + searchMode = "contains" + searchFields = "label,description" + minSearchLength = 0 + searchResultLimit = 0 + maxSelections = 0 + showCounter = false + counterTemplate = "{selected} selected" + optionTemplate = "default" + selectedTemplate = "default" + closeOnSelect = true + scrollToSelected = true + fixed = false + placement = "bottom" + remote = false + remoteUrl = "" + remoteQueryParam = "q" + remoteDebounce = 250 + remoteAutoLoad = true + infinite = false + hasMore = false + page = 1 + class = "" + @event search = function + @event select = function + @event change = function + @event clear = function + @event open = function + @event close = function + @event load = function + @event error = function + } + + state open = defaultOpen + state query = "" + state activeIndex = -1 + state selectedValue = value + state selectedValues = values + + functions { + function allOptions() { + return [...groups.flatMap((group) => group.options || []), ...options] + } + + function searchableText(option) { + return ((option.label || "") + " " + (option.description || "")).toLowerCase() + } + + function matches(option) { + if (!query || query.length < Number(minSearchLength || 0)) { + return true + } + if (searchMode === "startsWith") { + return searchableText(option).startsWith(query.toLowerCase()) + } + if (searchMode === "exact") { + return searchableText(option) === query.toLowerCase() + } + return searchableText(option).includes(query.toLowerCase()) + } + + function matchingOptions(list) { + return list.filter((option) => matches(option)) + } + + function visibleOptions(list) { + if (searchResultLimit > 0) { + return matchingOptions(list).slice(0, Number(searchResultLimit)) + } + return matchingOptions(list) + } + + function flatVisibleOptions() { + return visibleOptions(allOptions()) + } + + function isSelected(option) { + return ( + multiple + ? selectedValues.includes(option.value) + : selectedValue === option.value + ) + } + + function selectedOptions() { + return allOptions().filter((option) => isSelected(option)) + } + + function selectedCount() { + return multiple ? selectedValues.length : selectedValue ? 1 : 0 + } + + function counterText() { + return ( + maxSelections + ? selectedCount() + " / " + maxSelections + " selected" + : selectedCount() + " selected" + ) + } + + function selectedText() { + return ( + multiple + ? selectedValues.join(", ") + : selectedOptions().length + ? selectedOptions()[0].label + : "" + ) + } + + function triggerText() { + return selectedCount() ? selectedText() : placeholder + } + + function canSelect(option) { + if (option.disabled) { + return false + } + if (!multiple || isSelected(option)) { + return true + } + if (maxSelections <= 0) { + return true + } + return selectedCount() < maxSelections + } + + function chooseSingle(option) { + if (!canSelect(option)) { + return + } + selectedValue = option.value + query = "" + if (closeOnSelect) { + open = false + } + } + + function chooseMultiple(option) { + if (!canSelect(option)) { + return + } + if (isSelected(option)) { + selectedValues = selectedValues.filter((item) => item !== option.value) + } else { + selectedValues = selectedValues.concat([option.value]) + } + query = "" + } + + function chooseOption(option) { + if (multiple) { + chooseMultiple(option) + return + } + chooseSingle(option) + } + + function clearSelection(event) { + event.stopPropagation() + selectedValue = "" + selectedValues = [] + query = "" + open = false + } + + function toggle() { + if (disabled) { + return; + }; + open = !open; + activeIndex = open && flatVisibleOptions().length ? 0 : -1; + } + + function moveActive(direction) { + if (!flatVisibleOptions().length) { + return + } + activeIndex = (activeIndex + direction + flatVisibleOptions().length) % flatVisibleOptions().length + } + + function handleKeydown(event) { + if (disabled) { + return + } + if (event.key === "ArrowDown") { + event.preventDefault() + if (!open) { + open = true + } + moveActive(1) + } else if (event.key === "ArrowUp") { + event.preventDefault() + if (!open) { + open = true + } + moveActive(-1) + } else if (event.key === "Enter" || event.key === " ") { + event.preventDefault() + if (!open) { + open = true + } else if (activeIndex >= 0) { + chooseOption(flatVisibleOptions()[activeIndex]) + } + } else if (event.key === "Escape") { + open = false + } else if (event.key === "Home" && open) { + event.preventDefault() + activeIndex = 0 + } else if (event.key === "End" && open) { + event.preventDefault() + activeIndex = flatVisibleOptions().length - 1 + } + } + + function optionIndex(option) { + return flatVisibleOptions().findIndex((item) => item.value === option.value) + } + } + + view { +
+
+ + {counterText()} +
+ +
+ + + +
+ +
+ {#if searchable} + + {/if} + +
Enter at least {minSearchLength} characters.
+
+ + {loadingLabel} +
+
+ {#each groups as group} + {#if visibleOptions(group.options || []).length} +
+
{group.label}
+ {#each group.options || [] as option} + + {/each} +
+ {/if} + {/each} + + {#each options as option} + + {/each} + + {#if !loading && !flatVisibleOptions().length} +
{emptyLabel}
+ {/if} +
+ + {#if tags && query && !allOptions().some((option) => option.label.toLowerCase() === query.toLowerCase())} + + {/if} + +
+ + + + {#if helpText && !validationMessage}{helpText}{/if} + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AnnouncementBar.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AnnouncementBar.wrn new file mode 100644 index 00000000..3e7341f8 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AnnouncementBar.wrn @@ -0,0 +1,131 @@ +component AnnouncementBar { + props { + badge = "" + badgeIcon = "" + message = "Announcement" + description = "" + icon = "icon-[lucide--megaphone]" + actionLabel = "" + actionHref = "" + actionIcon = "" + dismissible = false + dismissLabel = "Dismiss announcement" + sticky = false + compact = false + size = "default" + color = "primary" + variant = "soft" + role = "status" + live = "polite" + class = "" + } + + state dismissed = false + + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AuthForm.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AuthForm.wrn new file mode 100644 index 00000000..489e0fb4 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AuthForm.wrn @@ -0,0 +1,84 @@ +component AuthForm { + props { + @event submit = function + @event change = function + @event input = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + mode = "sign-in" + action = "/api/auth/login" + method = "post" + title = "Sign in" + description = "" + returnTo = "" + schema = "" + showRemember = true + showName = true + submitLabel = "Continue" + class = "" + } + + functions { + function schemaName() { + if (schema) return schema + if (mode === "sign-in") return "auth-login" + if (mode === "register") return "auth-register" + if (mode === "recover") return "auth-password-request" + if (mode === "reset") return "auth-password-reset" + if (mode === "mfa") return "auth-mfa" + return "auth-empty" + } + + function submitForm(event) { + $emit("submit", { event: event, mode: mode, action: action }) + } + function fieldEvent(type, event) { + const detail = event.detail || {} + $emit(type, { event: event, name: detail.name || "", value: detail.value || "" }) + } + } + + view { +
+
+ +

{title}

{#if description}

{description}

{/if}
+
+
+ {#if returnTo}{/if} + {#if mode === "register" && showName} + + {/if} + {#if mode === "sign-in" || mode === "register" || mode === "recover"} + + {/if} + {#if mode === "sign-in" || mode === "register" || mode === "reset"} + + {/if} + {#if mode === "register" || mode === "reset"} + + {/if} + {#if mode === "mfa"} + + {/if} + {#if mode === "sign-in" && showRemember} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AuthSplitLayout.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AuthSplitLayout.wrn new file mode 100644 index 00000000..771c2902 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AuthSplitLayout.wrn @@ -0,0 +1,83 @@ +component AuthSplitLayout { + props { + size = "default" + color = "primary" + eyebrow = "Secure identity" + title = "Welcome back" + description = "" + brand = "Police Management System" + features = [] + class = "" + } + + view { +
+
+
+ + {brand}Unified identity and access +
+
+ + {eyebrow} + +

{title}

+ {#if description} +

{description}

+ {/if} +
+ {#each features as item} +
+ + {item.label} + {#if item.description} + {item.description} + {/if} + +
+ {/each} +
+ +
+ + Authorised access only · Activity may be monitored and audited. + +
+
+
+ +
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AvatarGroup.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AvatarGroup.wrn new file mode 100644 index 00000000..45623306 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/AvatarGroup.wrn @@ -0,0 +1,151 @@ +component AvatarGroup { + props { + items = [] + size = "md" + color = "primary" + variant = "solid" + shape = "circle" + layout = "stack" + maxVisible = 4 + columns = 3 + borderColor = "" + showTooltips = true + overflowLabel = "Show remaining members" + class = "" + + @event overflow = function + } + + state overflowOpen = false + + functions { + function visibleMembers() { + return items.slice(0, Number(maxVisible)) + } + + function hiddenMembers() { + return items.slice(Number(maxVisible)) + } + + function toggleOverflow(sourceEvent, root, customEvent) { + overflowOpen = !overflowOpen + root = sourceEvent.currentTarget.closest("[data-wrn-avatar-group]") + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("overflow", true, false, { + component: "AvatarGroup", + open: overflowOpen, + hiddenCount: hiddenMembers().length + }) + root.dispatchEvent(customEvent) + } + } + + view { +
+
+ {#each visibleMembers() as item} + + + {#if item.src} + {item.alt || item.name || ''} + {:else if item.initials} + + {:else} + + {/if} + + + {#if showTooltips && (item.tooltip || item.name)} + + {item.tooltip || item.name} + + {/if} + + {/each} + + {#if hiddenMembers().length > 0} + + + + + {#each hiddenMembers() as item} + + + {#if item.src} + + {:else} + {item.initials || '?'} + {/if} + + {item.name || item.alt || item.initials || 'Team member'} + + {/each} + + + {/if} +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/BackToTop.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/BackToTop.wrn new file mode 100644 index 00000000..42d2e157 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/BackToTop.wrn @@ -0,0 +1,69 @@ +component BackToTop { + props { + threshold = 500 + label = "Back to top" + ariaLabel = "Scroll back to top" + icon = "icon-[lucide--arrow-up]" + position = "right" + offset = "md" + behavior = "smooth" + showProgress = false + size = "default" + color = "primary" + variant = "solid" + class = "" + } + + state visible = false + state progress = 0 + + view { + + } + + style { + .wire-back-to-top-progress { + background: conic-gradient( + currentColor var(--wire-back-to-top-progress), + transparent var(--wire-back-to-top-progress) + ); + opacity: 0.22; + } + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Badge.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Badge.wrn new file mode 100644 index 00000000..e5eb1c9b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Badge.wrn @@ -0,0 +1,102 @@ +component Badge { + props { + label = "Badge" + size = "md" + color = "primary" + variant = "solid" + shape = "pill" + class = "" + + icon = "" + iconPosition = "start" + dot = false + dotOnly = false + dotLabel = "Status" + animated = false + + avatarSrc = "" + avatarAlt = "" + dismissible = false + dismissLabel = "Remove badge" + truncate = false + maxWidth = "12rem" + + anchorLabel = "" + anchorIcon = "" + placement = "inline" + anchorLabelText = "Badge anchor" + + @event dismiss = function + } + + state visible = true + + functions { + function dismissBadge(sourceEvent, root, customEvent) { + visible = false + root = sourceEvent.currentTarget.closest("[data-wrn-badge]") + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("dismiss", true, false, { + component: "Badge", + label: label + }) + root.dispatchEvent(customEvent) + } + } + + view { + + {#if anchorLabel || anchorIcon} + + {/if} + + + {#if animated} + + {/if} + {#if avatarSrc} + {avatarAlt} + {/if} + {#if dot || dotOnly} + + {/if} + {#if icon && iconPosition === "start"} + + {/if} + {#if !dotOnly} + + {label} + + {/if} + {#if icon && iconPosition === "end"} + + {/if} + {#if dismissible} + + {/if} + + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Blockquote.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Blockquote.wrn new file mode 100644 index 00000000..dc476675 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Blockquote.wrn @@ -0,0 +1,67 @@ +component Blockquote { + props { + quote = "I just wanted to say that I'm very happy with my purchase so far. The documentation is outstanding - clear and detailed." + citation = "" + citationTitle = "" + citationUrl = "" + avatarSrc = "" + avatarAlt = "" + size = "md" + color = "primary" + align = "left" + variant = "default" + quoteMark = true + italic = true + class = "" + } + + view { +
+
+ {#if quoteMark} + + {/if} + +
+ {#if quote} +

{quote}

+ {:else} + + {/if} +
+
+ + {#if citation || citationTitle || avatarSrc} +
+ {#if avatarSrc} + {avatarAlt} + {/if} + + + {#if citation} + {#if citationUrl} + {citation} + {:else} + {citation} + {/if} + {/if} + {#if citationTitle}{citationTitle}{/if} + +
+ {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Breadcrumb.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Breadcrumb.wrn new file mode 100644 index 00000000..1fee40b5 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Breadcrumb.wrn @@ -0,0 +1,19 @@ +component Breadcrumb { + props { + @event navigate = function + @event click = function + size = "default" + color = "primary" + label = "Breadcrumb" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ButtonGroup.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ButtonGroup.wrn new file mode 100644 index 00000000..7430aba7 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ButtonGroup.wrn @@ -0,0 +1,89 @@ +component ButtonGroup { + props { + @event click = function + @event select = function + @event change = function + items = [] + value = "" + size = "md" + color = "primary" + variant = "default" + orientation = "horizontal" + responsive = false + attached = true + selectable = false + toolbar = false + disabled = false + ariaLabel = "Button group" + class = "" + } + + state selectedValue = value + + functions { + function itemValue(item, index) { + return item.value || item.label || String(index) + } + + function selectItem(item, index) { + previousValue = selectedValue + nextValue = itemValue(item, index) + + $emit("select", { + value: nextValue, + previousValue: previousValue, + item: item, + index: index + }) + + if (selectable && previousValue !== nextValue) { + selectedValue = nextValue + $emit("change", { + value: nextValue, + previousValue: previousValue, + item: item, + index: index + }) + } + } + } + + view { +
+ {#if items} + {#each items as item, index} + + {/each} + {/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/CTASection.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/CTASection.wrn new file mode 100644 index 00000000..36453a83 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/CTASection.wrn @@ -0,0 +1,150 @@ +component CTASection { + props { + eyebrow = "" + title = "Ready to get started?" + description = "" + icon = "" + align = "center" + size = "default" + color = "primary" + variant = "solid" + primaryLabel = "Get started" + primaryHref = "#" + primaryIcon = "" + secondaryLabel = "" + secondaryHref = "" + secondaryIcon = "" + backgroundImage = "" + maxWidth = "xl" + class = "" + } + + view { +
+
+ {#if backgroundImage} + + {/if} + + + + +
+
+ {#if icon} + + + + {/if} + + {#if eyebrow} +

+ {eyebrow} +

+ {/if} + +

+ {title} +

+ + {#if description} +

+ {description} +

+ {/if} + + +
+ + + + + + +
+ + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Card.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Card.wrn new file mode 100644 index 00000000..5e9da9bd --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Card.wrn @@ -0,0 +1,284 @@ +component Card { + props { + @event click = function + @event action = function + @event navigate = function + @event dismiss = function + @event load = function + @event error = function + title = "Card title" + subtitle = "" + description = "" + header = "" + footer = "" + imageSrc = "" + imageAlt = "" + imagePosition = "top" + actionLabel = "" + actionHref = "" + headerActions = [] + navigation = [] + activeNav = "" + mobileNavigation = false + alertTitle = "" + alertDescription = "" + empty = false + emptyTitle = "No data to show" + emptyIcon = "icon-[lucide--inbox]" + items = [] + size = "md" + color = "primary" + variant = "default" + layout = "vertical" + align = "left" + hover = "none" + scrollable = false + maxHeight = "18rem" + dismissible = false + ariaLabel = "" + class = "" + } + + state dismissed = false + + view { +
+ {#if items.length > 0} +
+ {#each items as item, itemIndex} +
+ {#if item.imageSrc || item.image} +
+ {item.imageAlt || item.alt || ""} +
+ {/if} + +
+ {#if item.title || item.label} +

{item.title || item.label}

+ {/if} + {#if item.subtitle} +

{item.subtitle}

+ {/if} + {#if item.description} +

{item.description}

+ {/if} + {#if item.actionLabel || item.href} + + {item.actionLabel || "Learn more"} + + + {/if} +
+
+ {/each} +
+ {:else} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Chart.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Chart.wrn new file mode 100644 index 00000000..d491c5ae --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Chart.wrn @@ -0,0 +1,22 @@ +component Chart { + props { + @event select = function + @event dataPointClick = function + @event legendToggle = function + size = "default" + color = "primary" + title = "Chart" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ChatBubble.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ChatBubble.wrn new file mode 100644 index 00000000..947f6995 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ChatBubble.wrn @@ -0,0 +1,147 @@ +component ChatBubble { + props { + @event action = function + @event messageClick = function + @event avatarClick = function + @event linkClick = function + size = "default" + color = "primary" + title = "" + description = "" + items = [] + oneSided = false + showAvatars = false + showMetadata = false + ariaLabel = "Conversation" + variant = "default" + class = "" + } + + functions { + function messageDirection(item) { + return item.direction === "outgoing" ? "outgoing" : "incoming" + } + + function selectMessage(item, index) { + $emit("messageClick", { + item: item, + index: index, + direction: messageDirection(item) + }) + } + + function selectAvatar(sourceEvent, item, index) { + sourceEvent.stopPropagation() + $emit("avatarClick", { + item: item, + index: index, + direction: messageDirection(item) + }) + } + + function selectLink(sourceEvent, link, item, index) { + sourceEvent.stopPropagation() + $emit("linkClick", { + link: link, + item: item, + index: index + }) + } + + function selectAction(sourceEvent, item, index) { + sourceEvent.stopPropagation() + $emit("action", { + action: item.action || "retry", + item: item, + index: index + }) + } + } + + view { +
+ {#if title || description} +
+ {#if title}

{title}

{/if} + {#if description}

{description}

{/if} +
+ {/if} + + {#if items.length} +
+ {#each items as item, index} +
+
+ {#if showAvatars && (item.avatarSrc || item.avatarFallback)} + + {/if} + +
+ {#if item.title}

{item.title}

{/if} + {#if item.text}

{item.text}

{/if} + {#if item.bullets && item.bullets.length} +
    + {#each item.bullets as bullet}
  • {bullet}
  • {/each} +
+ {/if} + {#if item.links && item.links.length} + + {/if} +
+
+ + {#if showMetadata && (item.timestamp || item.status || item.actionLabel)} +
+ {#if item.statusIcon}{/if} + {#if item.status}{item.status}{/if} + {#if item.timestamp}{/if} + {#if item.actionLabel} + + {/if} +
+ {/if} +
+ {/each} +
+ {/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Checkbox.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Checkbox.wrn new file mode 100644 index 00000000..b945892e --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Checkbox.wrn @@ -0,0 +1,173 @@ +component Checkbox { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Checkbox" + hiddenLabel = false + placeholder = "" + variant = "normal" + icon = "" + iconPosition = "start" + value = "on" + values = [] + options = [] + checked = false + indeterminate = false + orientation = "vertical" + card = false + rightAligned = false + list = false + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { checked: sourceEvent.currentTarget.checked, value: sourceEvent.currentTarget.value, values: values, name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
+ {#if options.length || cornerHint} + + {label} + + {#if cornerHint} + + {cornerHint} + + {/if} + {/if} +
+ {#if options.length} +
+ {#each options as option} + + {/each} +
+ {:else} +
+ +
+ {/if} + {#if helperText} + + {helperText} + + {/if} + + {error} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Clipboard.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Clipboard.wrn new file mode 100644 index 00000000..09893a4a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Clipboard.wrn @@ -0,0 +1,22 @@ +component Clipboard { + props { + @event copy = function + @event success = function + @event error = function + size = "default" + color = "primary" + title = "Clipboard" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Collapse.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Collapse.wrn new file mode 100644 index 00000000..531c31f1 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Collapse.wrn @@ -0,0 +1,95 @@ +component Collapse { + props { + @event toggle = function + @event open = function + @event close = function + size = "default" + color = "primary" + items = [] + multiple = false + mode = "panel" + initialOpenIndexes = [] + ariaLabel = "Collapsible content" + class = "" + } + + state openIndexes = initialOpenIndexes + + functions { + function isOpen(index) { + return openIndexes.includes(index) + } + + function toggleItem(index, item, opening) { + if (item.disabled) { + return + } + opening = !isOpen(index) + if (opening) { + if (multiple) { + openIndexes = openIndexes.concat(index) + } else { + openIndexes = [index] + } + $emit("open", { index: index, item: item }) + } else { + openIndexes = openIndexes.filter((openIndex) => openIndex !== index) + $emit("close", { index: index, item: item }) + } + $emit("toggle", { + index: index, + item: item, + open: opening, + openIndexes: openIndexes + }) + } + } + + view { +
+ {#each items as item, index} +
+ {#if mode === "inline" && item.preview} +

{item.preview}

+ {/if} + + + +
+
+ {#if item.title}

{item.title}

{/if} + {#if item.content}

{item.content}

{/if} + {#if item.links && item.links.length} + + {/if} +
+
+
+ {/each} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ColorPicker.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ColorPicker.wrn new file mode 100644 index 00000000..0ba19a3a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ColorPicker.wrn @@ -0,0 +1,38 @@ +component ColorPicker { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Color" + hiddenLabel = false + placeholder = "" + value = "#2563eb" + icon = "" + iconPosition = "start" + helperText = "" + cornerHint = "" + error = "" + inline = false + variant = "normal" + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
{#if icon}{/if}{value}
+ {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Columns.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Columns.wrn new file mode 100644 index 00000000..96ac7ad1 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Columns.wrn @@ -0,0 +1,35 @@ +component Columns { + props { + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + + view { +
+ +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Combobox.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Combobox.wrn new file mode 100644 index 00000000..7f82992b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Combobox.wrn @@ -0,0 +1,386 @@ +component ComboBox { + props { + size = "default" + color = "primary" + label = "ComboBox" + name = "" + value = "" + options = [] + groups = [] + placeholder = "Search or select an option" + searchPlaceholder = "Start typing…" + clearable = true + allowCustomValue = false + disabled = false + required = false + invalid = false + validationMessage = "" + helpText = "" + loading = false + loadingLabel = "Loading suggestions…" + emptyLabel = "No matching options" + clearLabel = "Clear value" + toggleLabel = "Toggle suggestions" + searchMode = "contains" + searchFields = "label,description" + minSearchLength = 0 + searchResultLimit = 0 + optionTemplate = "default" + defaultOpen = false + closeOnSelect = true + fixed = false + placement = "bottom" + autocomplete = "off" + remote = false + remoteUrl = "" + remoteQueryParam = "q" + remoteDebounce = 250 + remoteAutoLoad = true + infinite = false + hasMore = false + page = 1 + loadMoreLabel = "Load more" + class = "" + @event search = function + @event select = function + @event change = function + @event clear = function + @event open = function + @event close = function + @event load = function + @event error = function + } + + state open = defaultOpen + state query = "" + state selectedValue = value + state activeIndex = -1 + + functions { + function allOptions() { + return [...groups.flatMap((group) => group.options || []), ...options] + } + + function searchableText(option) { + return ((option.label || "") + " " + (option.description || "")).toLowerCase() + } + + function matches(option) { + if (!query || query.length < minSearchLength) { + return true + } + if (searchMode === "startsWith") { + return searchableText(option).startsWith(query.toLowerCase()) + } + if (searchMode === "exact") { + return searchableText(option) === query.toLowerCase() + } + return searchableText(option).includes(query.toLowerCase()) + } + + function matchingOptions(list) { + return list.filter((option) => matches(option)) + } + + function visibleOptions(list) { + if (searchResultLimit > 0) { + return matchingOptions(list).slice(0, searchResultLimit) + } + return matchingOptions(list) + } + + function flatVisibleOptions() { + return visibleOptions(allOptions()) + } + + function isSelected(option) { + return selectedValue === option.value + } + + function selectedOptions() { + return allOptions().filter((option) => isSelected(option)) + } + + function selectedText() { + return selectedOptions().length ? selectedOptions()[0].label : selectedValue + } + + function inputText() { + return query || selectedText() + } + + function shouldShowDropdown() { + if (!open) { + return false + } + if (loading) { + return true + } + if (remote && query.length !== 0 && query.length < minSearchLength) { + return true + } + if (flatVisibleOptions().length) { + return true + } + return infinite && hasMore + } + + function canSelect(option) { + return !option.disabled + } + + function chooseOption(option) { + if (!canSelect(option)) { + return + } + selectedValue = option.value + query = option.label + activeIndex = optionIndex(option) + if (closeOnSelect) { + open = false + } + } + + function updateQuery(event) { + query = event.target.value + selectedValue = allowCustomValue ? event.target.value : "" + open = true + activeIndex = flatVisibleOptions().length ? 0 : -1 + } + + function clearValue(event) { + if (event) { + event.stopPropagation() + } + query = "" + selectedValue = "" + activeIndex = -1 + open = false + } + + function openDropdown() { + if (!disabled) { + open = true + activeIndex = flatVisibleOptions().length ? 0 : -1 + } + } + + function closeDropdown() { + open = false + } + + function toggle() { + if (open) { + closeDropdown() + } else { + openDropdown() + } + } + + function setValue(nextValue) { + selectedValue = nextValue + query = "" + } + + function moveActive(direction) { + if (!flatVisibleOptions().length) { + return + } + activeIndex = (activeIndex + direction + flatVisibleOptions().length) % flatVisibleOptions().length + } + + function handleKeydown(event) { + if (disabled) { + return + } + if (event.key === "ArrowDown") { + event.preventDefault() + openDropdown() + moveActive(1) + } else if (event.key === "ArrowUp") { + event.preventDefault() + openDropdown() + moveActive(-1) + } else if (event.key === "Enter" && open && activeIndex >= 0) { + event.preventDefault() + chooseOption(flatVisibleOptions()[activeIndex]) + } else if (event.key === "Escape") { + closeDropdown() + } else if (event.key === "Home" && open) { + event.preventDefault() + activeIndex = 0 + } else if (event.key === "End" && open) { + event.preventDefault() + activeIndex = flatVisibleOptions().length - 1 + } + } + + function optionIndex(option) { + return flatVisibleOptions().findIndex((item) => item.value === option.value) + } + } + + view { +
+ + +
+ + + + + +
+ +
+
Enter at least {minSearchLength} characters.
+
+ + {loadingLabel} +
+ +
+ {#each groups as group} + {#if visibleOptions(group.options || []).length} +
+
{group.label}
+ {#each group.options || [] as option} + + {/each} +
+ {/if} + {/each} + + {#each options as option} + + {/each} +
+ + +
+ + {#if !allowCustomValue} + + {/if} + + {#if helpText && !validationMessage}{helpText}{/if} + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Confetti.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Confetti.wrn new file mode 100644 index 00000000..26bbf788 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Confetti.wrn @@ -0,0 +1,21 @@ +component Confetti { + props { + @event start = function + @event complete = function + size = "default" + color = "primary" + title = "Confetti" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Container.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Container.wrn new file mode 100644 index 00000000..bcc3a50f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Container.wrn @@ -0,0 +1,46 @@ +component Container { + props { + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + + view { +
+ +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ContextMenu.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ContextMenu.wrn new file mode 100644 index 00000000..7a8b1264 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ContextMenu.wrn @@ -0,0 +1,22 @@ +component ContextMenu { + props { + @event open = function + @event close = function + @event select = function + size = "default" + color = "primary" + title = "Context Menu" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { +
+
{title}
+ {#if description}

{description}

{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/CopyMarkup.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/CopyMarkup.wrn new file mode 100644 index 00000000..ab506a30 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/CopyMarkup.wrn @@ -0,0 +1,23 @@ +component CopyMarkup { + props { + @event copy = function + @event success = function + @event error = function + size = "default" + color = "primary" + label = "Copy Markup" + name = "" + value = "" + placeholder = "" + type = "text" + min = "" + max = "" + step = "" + disabled = false + required = false + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/CustomScrollbar.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/CustomScrollbar.wrn new file mode 100644 index 00000000..37ace07c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/CustomScrollbar.wrn @@ -0,0 +1,14 @@ +component CustomScrollbar { + props { + @event scroll = function + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + view { +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DataMap.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DataMap.wrn new file mode 100644 index 00000000..49a30b5e --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DataMap.wrn @@ -0,0 +1,21 @@ +component DataMap { + props { + @event select = function + @event change = function + size = "default" + color = "primary" + title = "Data Map" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DataTable.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DataTable.wrn new file mode 100644 index 00000000..3ff347ea --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DataTable.wrn @@ -0,0 +1,19 @@ +component DataTable { + props { + @event sort = function + @event select = function + @event change = function + @event rowClick = function + @event pageChange = function + size = "default" + color = "primary" + caption = "Data Table" + columns = [] + rows = [] + striped = true + class = "" + } + view { +
{#each columns as column}{/each}{#each rows as row}{#each columns as column}{/each}{/each}
{caption}
{column.label}
{row[column.key]}
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DatePicker.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DatePicker.wrn new file mode 100644 index 00000000..b7682e5f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DatePicker.wrn @@ -0,0 +1,59 @@ +component DatePicker { + props { + @event input = function + @event change = function + @event open = function + @event close = function + @event focus = function + @event blur = function + @event invalid = function + size = "default" + color = "primary" + label = "Date Picker" + id = "" + name = "" + value = "" + placeholder = "" + type = "date" + locale = "en-US" + firstDayOfWeek = 0 + months = [{ label: "Jan", value: "01" }, { label: "Feb", value: "02" }, { label: "Mar", value: "03" }, { label: "Apr", value: "04" }, { label: "May", value: "05" }, { label: "Jun", value: "06" }, { label: "Jul", value: "07" }, { label: "Aug", value: "08" }, { label: "Sep", value: "09" }, { label: "Oct", value: "10" }, { label: "Nov", value: "11" }, { label: "Dec", value: "12" }] + days = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31] + years = [2024, 2025, 2026, 2027, 2028, 2029, 2030] + min = "" + max = "" + step = "" + helperText = "" + cornerHint = "" + error = "" + variant = "normal" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + state currentValue = value + state selectedYear = value ? value.split("-")[0] : "" + state selectedMonth = value ? value.split("-")[1] : "" + state selectedDay = value ? value.split("-")[2] : "" + state expanded = false + functions { + function openCalendar(sourceEvent) { expanded = true; $emit("open", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function updateDate(part, nextValue, sourceEvent, nextDate, detail) { if (part === "year") { selectedYear = String(nextValue) } if (part === "month") { selectedMonth = String(nextValue).padStart(2, "0") } if (part === "day") { selectedDay = String(nextValue).padStart(2, "0") } if (!selectedYear || !selectedMonth || !selectedDay) { return } nextDate = selectedYear + "-" + selectedMonth + "-" + selectedDay; if ((min && nextDate < min) || (max && nextDate > max)) { return } currentValue = nextDate; detail = { value: currentValue, year: selectedYear, month: selectedMonth, day: selectedDay, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function finishDate(sourceEvent) { if (!currentValue) { return } expanded = false; $emit("close", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function selectDay(sourceEvent, root, input, nextDate, trigger, detail) { root = sourceEvent.currentTarget.closest(".wire-next--date-picker"); input = root.querySelector(".wire-next__picker-value"); nextDate = input.getAttribute("value").slice(0, 5) + root.querySelector("select").getAttribute("value") + "-" + sourceEvent.currentTarget.dataset.value; currentValue = nextDate; input.setAttribute("value", nextDate); trigger = root.querySelector(".wire-next__date-trigger span"); if (trigger) { trigger.replaceChildren(nextDate) } sourceEvent.currentTarget.setAttribute("aria-pressed", "true"); detail = { value: nextDate, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function clearDate(sourceEvent, detail) { if (disabled || readonly) { return } currentValue = ""; detail = { value: currentValue, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function handleFocus(sourceEvent) { $emit("focus", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleBlur(sourceEvent) { $emit("blur", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleInvalid(sourceEvent) { $emit("invalid", { name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
{#if currentValue && !readonly && !disabled}{/if}
+ + {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DeviceFrame.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DeviceFrame.wrn new file mode 100644 index 00000000..f2d3d891 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DeviceFrame.wrn @@ -0,0 +1,31 @@ +component DeviceFrame { + props { + @event change = function + @event rotate = function + size = "default" + color = "primary" + title = "Device Frame" + description = "" + items = [] + variant = "default" + device = "phone" + orientation = "portrait" + src = "" + srcdoc = "" + frameTitle = "Device preview" + showToolbar = true + allow = "" + class = "" + } + state currentOrientation = orientation + functions { + function setDevice(nextDevice, sourceEvent) { $emit("change", { device: nextDevice, orientation: currentOrientation, sourceEvent: sourceEvent }) } + function rotateFrame(sourceEvent) { currentOrientation = currentOrientation === "portrait" ? "landscape" : "portrait"; $emit("rotate", { device: device, orientation: currentOrientation, sourceEvent: sourceEvent }); $emit("change", { device: device, orientation: currentOrientation, sourceEvent: sourceEvent }) } + } + view { +
+
{#if title}{title}{/if}{#if description}

{description}

{/if}
{#if showToolbar}{/if}
+
{#if src || srcdoc}{:else}
{/if}
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Divider.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Divider.wrn new file mode 100644 index 00000000..b7a19a9f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Divider.wrn @@ -0,0 +1,69 @@ +component Divider { + props { + size = "default" + color = "primary" + label = "" + orientation = "horizontal" + class = "" + } + + view { +
+ {#if orientation === "vertical"} + + {:else} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DragAndDrop.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DragAndDrop.wrn new file mode 100644 index 00000000..944dec48 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/DragAndDrop.wrn @@ -0,0 +1,25 @@ +component DragAndDrop { + props { + @event dragStart = function + @event dragEnd = function + @event dragEnter = function + @event dragLeave = function + @event drop = function + @event change = function + size = "default" + color = "primary" + title = "Drag And Drop" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Drawer.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Drawer.wrn new file mode 100644 index 00000000..641cef87 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Drawer.wrn @@ -0,0 +1,21 @@ +component Drawer { + props { + @event open = function + @event close = function + size = "default" + color = "primary" + title = "Drawer" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Dropdown.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Dropdown.wrn new file mode 100644 index 00000000..f73c1a6c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Dropdown.wrn @@ -0,0 +1,53 @@ +component Dropdown { + props { + @event toggle = function + @event open = function + @event close = function + @event select = function + size = "default" + color = "primary" + label = "Open menu" + items = [] + placement = "end" + class = "" + } + + functions { + function toggleMenu(event) { + $emit("toggle", { open: event.currentTarget.open }) + $emit(event.currentTarget.open ? "open" : "close", { source: "trigger" }) + } + + function selectItem(item) { + $emit("select", { item: item, value: item.value || "" }) + } + } + + view { +
+ + + + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FeatureCard.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FeatureCard.wrn new file mode 100644 index 00000000..93eb1906 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FeatureCard.wrn @@ -0,0 +1,113 @@ +component FeatureCard { + props { + icon = "" + title = "Feature" + description = "" + href = "" + actionLabel = "Learn more" + actionIcon = "" + badge = "" + badgeColor = "primary" + size = "default" + color = "primary" + variant = "default" + hover = "lift" + align = "left" + disabled = false + class = "" + } + + view { +
+
+
+ + {#if icon} + + {/if} +
+ + {#if badge} + + {/if} +
+ +

+ {title} +

+ + {#if description} +

+ {description} +

+ {/if} + + + +
+ + + {#if href && actionLabel} + + {/if} +
+ + {#if href} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FeatureGrid.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FeatureGrid.wrn new file mode 100644 index 00000000..aa9d45a0 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FeatureGrid.wrn @@ -0,0 +1,53 @@ +component FeatureGrid { + props { + columns = 3 + tabletColumns = 2 + mobileColumns = 1 + gap = "md" + minItemWidth = "" + equalHeight = true + align = "stretch" + maxWidth = "full" + class = "" + } + + view { +
+ +
+ } + + style { + .wire-feature-grid-autofit { + grid-template-columns: repeat(auto-fit, minmax(var(--wire-feature-grid-min), 1fr)); + } + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FeatureIconCard.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FeatureIconCard.wrn new file mode 100644 index 00000000..1b985d39 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FeatureIconCard.wrn @@ -0,0 +1,78 @@ +component FeatureIconCard { + props { + icon = "icon-[lucide--sparkles]" + iconSize = "md" + iconVariant = "soft" + title = "Feature" + description = "" + href = "" + actionLabel = "Explore" + badge = "" + size = "default" + color = "primary" + variant = "default" + align = "left" + hover = "lift" + class = "" + } + + view { +
+
+ + + {#if badge} + + {badge} + + {/if} +
+ +

{title}

+ + {#if description} +

{description}

+ {/if} + + + + {#if href} + + {/if} + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FileInput.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FileInput.wrn new file mode 100644 index 00000000..b3ed2183 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FileInput.wrn @@ -0,0 +1,52 @@ +component FileInput { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event select = function + @event clear = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "File" + hiddenLabel = false + placeholder = "Choose a file" + value = "" + icon = "icon-[lucide--upload]" + iconPosition = "start" + accept = "" + multiple = false + helperText = "" + cornerHint = "" + error = "" + inline = false + variant = "normal" + readonly = false + disabled = false + required = false + class = "" + } + state selectedName = "" + functions { + function handleChange(sourceEvent) { + sourceEvent.stopPropagation() + selectedName = sourceEvent.currentTarget.files && sourceEvent.currentTarget.files.length ? sourceEvent.currentTarget.files[0].name : "" + $emit("input", { files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent }) + $emit("change", { files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent }) + if (selectedName) $emit("select", { files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent }) + else $emit("clear", { name: name, sourceEvent: sourceEvent }) + } + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
{#if icon}{/if}{selectedName || value || placeholder}
+ {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FileUpload.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FileUpload.wrn new file mode 100644 index 00000000..207d3571 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FileUpload.wrn @@ -0,0 +1,26 @@ +component FileUpload { + props { + @event select = function + @event upload = function + @event progress = function + @event success = function + @event error = function + @event cancel = function + @event remove = function + size = "default" + color = "primary" + title = "File Upload" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FileUploadProgress.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FileUploadProgress.wrn new file mode 100644 index 00000000..329a5859 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/FileUploadProgress.wrn @@ -0,0 +1,37 @@ +component FileUploadProgress { + props { + @event cancel = function + @event retry = function + @event complete = function + size = "default" + color = "primary" + label = "Progress" + value = 50 + max = 100 + showValue = true + fileName = "" + fileSize = "" + uploadedSize = "" + status = "uploading" + cancelLabel = "Cancel upload" + retryLabel = "Retry upload" + class = "" + } + state currentValue = value + state currentStatus = status + functions { + function percent() { if (!Number(max)) { return 0 } return Math.max(0, Math.min(100, Math.round(Number(currentValue) / Number(max) * 100))) } + function detail(sourceEvent) { return { value: currentValue, max: max, percent: percent(), status: currentStatus, fileName: fileName, sourceEvent: sourceEvent } } + function cancelUpload(sourceEvent) { currentStatus = "cancelled"; $emit("cancel", detail(sourceEvent)) } + function retryUpload(sourceEvent) { currentValue = 0; currentStatus = "uploading"; $emit("retry", detail(sourceEvent)) } + function completeUpload(sourceEvent) { currentValue = max; currentStatus = "complete"; $emit("complete", detail(sourceEvent)) } + } + view { +
+
{#if fileName}{fileName}{#if uploadedSize || fileSize}{uploadedSize}{#if uploadedSize && fileSize} of {/if}{fileSize}{:else}{label}{/if}{:else}{label}{/if}{#if showValue}{percent()}%{/if}
+ +
{#if currentStatus === "uploading"}Uploading securely…{:else if currentStatus === "complete"}Upload complete{:else if currentStatus === "error"}Upload failed{:else}Upload cancelled{/if}
+
{#if currentStatus === "uploading"}{/if}{#if currentStatus === "error" || currentStatus === "cancelled"}{/if}
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Footer.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Footer.wrn new file mode 100644 index 00000000..e0f3ac1d --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Footer.wrn @@ -0,0 +1,144 @@ +component Footer { + props { + @event select = function + @event action = function + size = "default" + color = "primary" + label = "Footer navigation" + items = [] + columns = 3 + maxWidth = "compact" + copyright = "" + class = "" + } + + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Grid.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Grid.wrn new file mode 100644 index 00000000..b76a5447 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Grid.wrn @@ -0,0 +1,40 @@ +component Grid { + props { + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + + view { +
+ +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Hero.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Hero.wrn new file mode 100644 index 00000000..7613a2b6 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Hero.wrn @@ -0,0 +1,149 @@ +component Hero { + props { + eyebrow = "" + title = "Build something remarkable" + highlight = "" + description = "" + align = "left" + size = "default" + color = "primary" + variant = "default" + primaryLabel = "" + primaryHref = "" + primaryIcon = "" + secondaryLabel = "" + secondaryHref = "" + secondaryIcon = "" + tertiaryLabel = "" + tertiaryHref = "" + badges = [] + trustItems = [] + maxWidth = "xl" + class = "" + } + + view { +
+
+ {#if variant === "gradient"} + + {/if} + +
+ + + {#if eyebrow} +
+ + {eyebrow} +
+ {/if} + +

+ {title} + {#if highlight} + + {highlight} + + {/if} +

+ + {#if description} +

+ {description} +

+ {/if} + + {#if badges.length > 0} +
+ {#each badges as badge} + + {/each} +
+ {/if} + +
+ + + +
+ + {#if trustItems.length > 0} +
+ {#each trustItems as item} + + + {item.label || item.title || item} + + {/each} +
+ {/if} + + + +
+ +
+ +
+ + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/HeroActions.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/HeroActions.wrn new file mode 100644 index 00000000..28b0cc44 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/HeroActions.wrn @@ -0,0 +1,52 @@ +component HeroActions { + props { + actions = [] + align = "left" + orientation = "horizontal" + stackOnMobile = true + fullWidthMobile = true + size = "default" + color = "primary" + class = "" + } + + view { +
+ {#each actions as action, index} + {#if action.label} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Image.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Image.wrn new file mode 100644 index 00000000..881d5229 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Image.wrn @@ -0,0 +1,47 @@ +component Image { + props { + size = "default" + color = "primary" + src = "" + alt = "" + width = "" + height = "" + loading = "lazy" + rounded = false + class = "" + } + + view { +
+ {#if src} + {alt} + {:else} + + {/if} + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Input.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Input.wrn new file mode 100644 index 00000000..3e12c986 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Input.wrn @@ -0,0 +1,92 @@ +component Input { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event invalid = function + @event keydown = function + @event keyup = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Input" + hiddenLabel = false + placeholder = "" + value = "" + type = "text" + variant = "normal" + icon = "" + iconPosition = "start" + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + autocomplete = "" + inputmode = "" + minlength = "" + maxlength = "" + pattern = "" + min = "" + max = "" + step = "" + class = "" + } + functions { + function detail(sourceEvent) { + return { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent } + } + function handleInput(sourceEvent) { sourceEvent.stopPropagation(); $emit("input", detail(sourceEvent)) } + function handleChange(sourceEvent) { sourceEvent.stopPropagation(); $emit("change", detail(sourceEvent)) } + function handleFocus(sourceEvent) { sourceEvent.stopPropagation(); $emit("focus", detail(sourceEvent)) } + function handleBlur(sourceEvent) { sourceEvent.stopPropagation(); $emit("blur", detail(sourceEvent)) } + function handleInvalid(sourceEvent) { sourceEvent.stopPropagation(); $emit("invalid", { value: sourceEvent.currentTarget.value, name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } + function handleKeydown(sourceEvent) { sourceEvent.stopPropagation(); $emit("keydown", { key: sourceEvent.key, value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + function handleKeyup(sourceEvent) { sourceEvent.stopPropagation(); $emit("keyup", { key: sourceEvent.key, value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + } + view { +
+
+ + {#if cornerHint}{cornerHint}{/if} +
+
+ {#if icon}{/if} + + {#if variant === "floating"}{label}{/if} +
+ {#if helperText}{helperText}{/if} + {error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/InputGroup.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/InputGroup.wrn new file mode 100644 index 00000000..aea3fd7a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/InputGroup.wrn @@ -0,0 +1,51 @@ +component InputGroup { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event submit = function + @event action = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Input group" + hiddenLabel = false + value = "" + placeholder = "" + type = "text" + startText = "" + endText = "" + icon = "" + iconPosition = "start" + actionLabel = "" + helperText = "" + cornerHint = "" + error = "" + inline = false + variant = "normal" + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + function handleKeydown(sourceEvent) { if (sourceEvent.key === "Enter") { sourceEvent.stopPropagation(); $emit("submit", { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } } + function handleAction(sourceEvent) { $emit("action", { name: name, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if startText}{startText}{/if} + {#if icon}{/if} + + {#if endText}{endText}{/if} + {#if actionLabel}{/if} +
+ {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/InputNumber.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/InputNumber.wrn new file mode 100644 index 00000000..226922fd --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/InputNumber.wrn @@ -0,0 +1,623 @@ +component InputNumber { + props { + size = "default" + color = "primary" + variant = "default" + class = "" + + id = "" + name = "quantity" + value = 0 + min = "" + max = "" + step = 1 + precision = "auto" + + label = "" + description = "" + helpText = "" + error = "" + invalid = false + + prefix = "" + suffix = "" + placeholder = "" + autocomplete = "off" + inputMode = "decimal" + ariaLabel = "" + + required = false + disabled = false + inputDisabled = false + buttonsDisabled = false + readonly = false + allowInput = true + keyboard = true + wheel = false + clamp = true + fullWidth = false + showButtons = true + showValidationMessage = true + + decrementLabel = "Decrease value" + incrementLabel = "Increase value" + controlsLabel = "Quantity controls" + requiredMessage = "A value is required." + minMessage = "Value is below the minimum." + maxMessage = "Value is above the maximum." + + @event input = function + @event change = function + @event increment = function + @event decrement = function + } + + state currentValue = value + state committedValue = value + + functions { + function inputId() { + if (id !== "") { + return id + } + + if (name !== "") { + return name + } + + return "input-number" + } + + function descriptionId() { + return inputId() + "-description" + } + + function messageId() { + return inputId() + "-message" + } + + function componentColor() { + if (color === "secondary") { + return "var(--wire-color-secondary)" + } + + if (color === "success") { + return "var(--wire-color-success)" + } + + if (color === "warning") { + return "var(--wire-color-warning)" + } + + if (color === "danger") { + return "var(--wire-color-danger)" + } + + if (color === "info") { + return "var(--wire-color-info)" + } + + return "var(--wire-color-primary)" + } + + function hasMin() { + return min !== "" && min !== null && min !== undefined + } + + function hasMax() { + return max !== "" && max !== null && max !== undefined + } + + function isBlank() { + return currentValue === "" || currentValue === null || currentValue === undefined + } + + function normalizedStep() { + return Number(step) > 0 ? Number(step) : 1 + } + + function inferredPrecision() { + if (precision !== "auto" && precision !== "") { + return Math.max(0, Number(precision) || 0) + } + + if (String(normalizedStep()).includes(".")) { + return String(normalizedStep()).split(".")[1].length + } + + return 0 + } + + function precisionFactor() { + return Math.pow(10, inferredPrecision()) + } + + function roundValue(nextValue) { + return Math.round(Number(nextValue) * precisionFactor()) / precisionFactor() + } + + function clampValue(nextValue) { + nextValue = Number(nextValue) + + if (hasMin() && nextValue < Number(min)) { + nextValue = Number(min) + } + + if (hasMax() && nextValue > Number(max)) { + nextValue = Number(max) + } + + return roundValue(nextValue) + } + + function isBelowMin() { + return !isBlank() && hasMin() && Number(currentValue) < Number(min) + } + + function isAboveMax() { + return !isBlank() && hasMax() && Number(currentValue) > Number(max) + } + + function isInvalid() { + return ( + invalid || + error !== "" || + (required && isBlank()) || + isBelowMin() || + isAboveMax() + ) + } + + function validationMessage() { + if (error !== "") { + return error + } + + if (required && isBlank()) { + return requiredMessage + } + + if (isBelowMin()) { + return minMessage + } + + if (isAboveMax()) { + return maxMessage + } + + return "" + } + + function hasMessage() { + return ( + helpText !== "" || + (showValidationMessage && isInvalid() && validationMessage() !== "") + ) + } + + function describedBy() { + if (description !== "" && hasMessage()) { + return descriptionId() + " " + messageId() + } + + if (description !== "") { + return descriptionId() + } + + if (hasMessage()) { + return messageId() + } + + return "" + } + + function decrementDisabled() { + return ( + disabled || + readonly || + buttonsDisabled || + (hasMin() && !isBlank() && Number(currentValue) <= Number(min)) + ) + } + + function incrementDisabled() { + return ( + disabled || + readonly || + buttonsDisabled || + (hasMax() && !isBlank() && Number(currentValue) >= Number(max)) + ) + } + + function dispatchInputNumberEvent( + sourceEvent, + eventName, + action, + previousValue, + root, + customEvent + ) { + root = sourceEvent.currentTarget.closest("[data-wrn-input-number]") + + if (!root && sourceEvent.target) { + root = sourceEvent.target.closest("[data-wrn-input-number]") + } + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent(eventName, true, false, { + component: "InputNumber", + name: name, + value: currentValue, + previousValue: previousValue, + action: action, + min: hasMin() ? Number(min) : null, + max: hasMax() ? Number(max) : null, + step: normalizedStep(), + valid: !isInvalid() + }) + root.dispatchEvent(customEvent) + } + + function applyControlValue(nextValue, action, sourceEvent, previousValue) { + previousValue = currentValue + currentValue = clampValue(nextValue) + committedValue = currentValue + + dispatchInputNumberEvent( + sourceEvent, + "input", + action, + previousValue + ) + dispatchInputNumberEvent( + sourceEvent, + "change", + action, + previousValue + ) + dispatchInputNumberEvent( + sourceEvent, + action, + action, + previousValue + ) + } + + function incrementValue(sourceEvent, nextValue) { + if (incrementDisabled()) { + return + } + + if (isBlank()) { + nextValue = hasMin() ? Number(min) : normalizedStep() + } else { + nextValue = + Number(currentValue) + + normalizedStep() * (sourceEvent.shiftKey ? 10 : 1) + } + + applyControlValue(nextValue, "increment", sourceEvent) + } + + function decrementValue(sourceEvent, nextValue) { + if (decrementDisabled()) { + return + } + + if (isBlank()) { + nextValue = hasMax() ? Number(max) : -normalizedStep() + } else { + nextValue = + Number(currentValue) - + normalizedStep() * (sourceEvent.shiftKey ? 10 : 1) + } + + applyControlValue(nextValue, "decrement", sourceEvent) + } + + function handleInput(sourceEvent, previousValue, nextValue) { + sourceEvent.stopPropagation() + previousValue = currentValue + nextValue = sourceEvent.target.value + + if (nextValue === "") { + currentValue = "" + } else if (!Number.isNaN(Number(nextValue))) { + currentValue = roundValue(Number(nextValue)) + } + + dispatchInputNumberEvent( + sourceEvent, + "input", + "input", + previousValue + ) + } + + function handleChange(sourceEvent, previousValue) { + sourceEvent.stopPropagation() + previousValue = committedValue + + if (!isBlank()) { + currentValue = clamp + ? clampValue(currentValue) + : roundValue(currentValue) + } + + committedValue = currentValue + + dispatchInputNumberEvent( + sourceEvent, + "change", + "change", + previousValue + ) + } + + function handleKeydown(sourceEvent) { + if ( + !keyboard || + disabled || + readonly || + inputDisabled || + !allowInput + ) { + return + } + + if (sourceEvent.key === "ArrowUp") { + sourceEvent.preventDefault() + incrementValue(sourceEvent) + } else if (sourceEvent.key === "ArrowDown") { + sourceEvent.preventDefault() + decrementValue(sourceEvent) + } else if (sourceEvent.key === "Home" && hasMin()) { + sourceEvent.preventDefault() + applyControlValue(Number(min), "decrement", sourceEvent) + } else if (sourceEvent.key === "End" && hasMax()) { + sourceEvent.preventDefault() + applyControlValue(Number(max), "increment", sourceEvent) + } + } + + function handleWheel(sourceEvent) { + if ( + !wheel || + disabled || + readonly || + inputDisabled || + !allowInput + ) { + return + } + + sourceEvent.preventDefault() + + if (sourceEvent.deltaY < 0) { + incrementValue(sourceEvent) + } else if (sourceEvent.deltaY > 0) { + decrementValue(sourceEvent) + } + } + } + + view { +
+ {#if label !== "" && variant !== "labeled" && variant !== "seat"} + + {/if} + + {#if description !== "" && variant !== "labeled" && variant !== "seat"} +

+ {description} +

+ {/if} + +
+ {#if variant === "horizontal" && showButtons} + + {/if} + +
+ {#if variant === "labeled" || variant === "seat"} +
+ {#if label !== ""} + + {/if} + + {#if description !== ""} + + {description} + + {/if} +
+ {/if} + +
+ {#if prefix !== ""} + + {/if} + + + + {#if suffix !== ""} + + {/if} +
+
+ + {#if variant === "horizontal" && showButtons} + + {:else} + {#if showButtons} +
+ + + +
+ {/if} + {/if} +
+ + {#if showValidationMessage && isInvalid() && validationMessage() !== ""} + + {/if} + + {#if (!showValidationMessage || !isInvalid() || validationMessage() === "") && helpText !== ""} +

+ {helpText} +

+ {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Kbd.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Kbd.wrn new file mode 100644 index 00000000..e14edc4c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Kbd.wrn @@ -0,0 +1,9 @@ +component Kbd { + props { + size = "default" + color = "primary" + label = "⌘ K" + class = "" + } + view { {label} } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/LayoutSplitter.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/LayoutSplitter.wrn new file mode 100644 index 00000000..f9ad4d58 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/LayoutSplitter.wrn @@ -0,0 +1,16 @@ +component LayoutSplitter { + props { + @event resizeStart = function + @event resize = function + @event resizeEnd = function + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + view { +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/LegendIndicator.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/LegendIndicator.wrn new file mode 100644 index 00000000..1fae3791 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/LegendIndicator.wrn @@ -0,0 +1,21 @@ +component LegendIndicator { + props { + @event toggle = function + @event select = function + size = "default" + color = "primary" + title = "Legend Indicator" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Link.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Link.wrn new file mode 100644 index 00000000..3cf17764 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Link.wrn @@ -0,0 +1,47 @@ +component Link { + props { + size = "default" + color = "primary" + label = "Link" + href = "#" + target = "" + rel = "" + external = false + class = "" + } + + view { + + {label} + + {#if external} + + {/if} + + + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/List.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/List.wrn new file mode 100644 index 00000000..0ac667a7 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/List.wrn @@ -0,0 +1,107 @@ +component List { + props { + size = "default" + color = "primary" + title = "List" + description = "" + items = [] + variant = "default" + class = "" + } + + view { +
+ {#if title || description} +
+ {#if title} +

{title}

+ {/if} + {#if description} +

{description}

+ {/if} +
+ {/if} + + + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ListGroup.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ListGroup.wrn new file mode 100644 index 00000000..35366c9c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ListGroup.wrn @@ -0,0 +1,21 @@ +component ListGroup { + props { + @event select = function + @event change = function + size = "default" + color = "primary" + title = "List Group" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Map.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Map.wrn new file mode 100644 index 00000000..6d0da585 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Map.wrn @@ -0,0 +1,85 @@ +component Map { + props { + size = "default" + color = "primary" + title = "Map" + description = "" + items = [] + variant = "default" + class = "" + } + + view { +
+ {#if title || description} +
+
+ {#if title} +

{title}

+ {/if} + {#if description} +

{description}

+ {/if} +
+ + + +
+ {/if} + +
+ + +
+ +
+ + {#if items.length > 0} + {#each items as item, index} + + {/each} + {/if} + +
+ + +
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/MarketingSectionHeader.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/MarketingSectionHeader.wrn new file mode 100644 index 00000000..5d3d9de3 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/MarketingSectionHeader.wrn @@ -0,0 +1,59 @@ +component MarketingSectionHeader { + props { + id = "" + eyebrow = "" + title = "" + description = "" + align = "split" + size = "default" + color = "primary" + actionLabel = "" + actionHref = "" + actionIcon = "" + actionExternal = false + class = "" + } + + view { +
+ +
+ +
+ +
+ {#if actionLabel} + + {/if} + +
+ + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Marquee.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Marquee.wrn new file mode 100644 index 00000000..53d4ca7b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Marquee.wrn @@ -0,0 +1,111 @@ +component Marquee { + props { + size = "default" + color = "primary" + title = "Marquee" + description = "" + items = [] + variant = "default" + class = "" + } + + state paused = false + + view { +
+
+ {#if title} +
+ + {title} +
+ {/if} + +
+
+ {#each items as item} + + + {item.label || item.title} + {#if item.meta} + {item.meta} + {/if} + + {:empty} +

{description || "No announcements available."}

+ {/each} + + {#if items.length > 0} + {#each items as item} + + {/each} + {/if} +
+
+ + +
+ + +
+ } + + style { + .wire-marquee-track { + animation: wire-marquee 32s linear infinite; + } + + .wire-marquee-paused { + animation-play-state: paused; + } + + @keyframes wire-marquee { + from { transform: translateX(0); } + to { transform: translateX(-50%); } + } + + @media (prefers-reduced-motion: reduce) { + .wire-marquee-track { + animation: none; + } + } + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/MegaMenu.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/MegaMenu.wrn new file mode 100644 index 00000000..303025b0 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/MegaMenu.wrn @@ -0,0 +1,20 @@ +component MegaMenu { + props { + @event open = function + @event close = function + @event select = function + size = "default" + color = "primary" + label = "Mega Menu" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/MetricCard.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/MetricCard.wrn new file mode 100644 index 00000000..efc63fc4 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/MetricCard.wrn @@ -0,0 +1,107 @@ +component MetricCard { + props { + label = "Metric" + value = "0" + description = "" + icon = "" + prefix = "" + suffix = "" + trend = "" + trendLabel = "" + trendDirection = "neutral" + href = "" + actionLabel = "" + size = "default" + color = "primary" + variant = "default" + align = "left" + class = "" + } + + view { +
+
+
+

{label}

+

+ {prefix}{value}{suffix} +

+
+ + {#if icon} + + + + {/if} +
+ + {#if description} +

{description}

+ {/if} + + {#if trend || trendLabel} +
+ + {#if trendDirection === "up" || trendDirection === "positive"} + + {:else if trendDirection === "down" || trendDirection === "negative"} + + {:else} + + {/if} + {trend} + + {#if trendLabel} + {trendLabel} + {/if} +
+ {/if} + + {#if href} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/MetricGrid.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/MetricGrid.wrn new file mode 100644 index 00000000..5e353cff --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/MetricGrid.wrn @@ -0,0 +1,60 @@ +component MetricGrid { + props { + items = [] + columns = 4 + tabletColumns = 2 + mobileColumns = 1 + gap = "md" + equalHeight = true + dividers = false + size = "default" + color = "primary" + variant = "default" + class = "" + } + + view { +
+ {#each items as item} + + {:empty} + + {/each} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Modal.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Modal.wrn new file mode 100644 index 00000000..2366e70f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Modal.wrn @@ -0,0 +1,23 @@ +component Modal { + props { + @event open = function + @event close = function + @event cancel = function + @event confirm = function + size = "default" + color = "primary" + title = "Modal" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Nav.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Nav.wrn new file mode 100644 index 00000000..de980dc7 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Nav.wrn @@ -0,0 +1,19 @@ +component Nav { + props { + @event select = function + @event change = function + size = "default" + color = "primary" + label = "Nav" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Navbar.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Navbar.wrn new file mode 100644 index 00000000..b6f85083 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Navbar.wrn @@ -0,0 +1,140 @@ +component Navbar { + props { + @event toggle = function + @event open = function + @event close = function + @event select = function + @event action = function + size = "default" + color = "primary" + label = "Primary navigation" + topbarLabel = "Utility navigation" + brand = {} + items = [] + actions = [] + active = "" + sticky = false + openOnHover = false + maxWidth = "full" + mobileLabel = "Toggle navigation" + class = "" + } + + state mobileOpen = false + + functions { + function toggleNavigation() { + mobileOpen = !mobileOpen + $emit("toggle", { open: mobileOpen }) + $emit(mobileOpen ? "open" : "close", { source: "mobile" }) + } + + function selectItem(item, level) { + mobileOpen = false + $emit("select", { item: item, value: item.value || "", level: level }) + } + + function selectAction(item) { + mobileOpen = false + $emit("action", { item: item, value: item.value || "" }) + } + + function isItemActive(item) { + if (!item) return false + if (item.value && item.value === active) return true + if (!item.children || !item.children.length) return false + return item.children.some(function (child) { + return isItemActive(child) + }) + } + + function toggleDropdown(event, item) { + $emit(event.currentTarget.open ? "open" : "close", { + source: "menu", + item: item + }) + } + } + + view { +
+
+ +
+ +
+ + {#if brand.logo} + + {/if} + {#if brand.icon} + + {/if} + {#if brand.label || brand.description} + + {#if brand.label}{brand.label}{/if} + {#if brand.description}{brand.description}{/if} + + {/if} + + + + +
+ + +
+ {#each actions as item} + + {#if item.icon}{/if} + {item.label} + + {/each} + +
+
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PageHeader.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PageHeader.wrn new file mode 100644 index 00000000..42132045 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PageHeader.wrn @@ -0,0 +1,105 @@ +component PageHeader { + props { + eyebrow = "" + title = "" + description = "" + icon = "" + align = "left" + size = "default" + compact = false + showBreadcrumbs = false + breadcrumbs = [] + primaryLabel = "" + primaryHref = "" + primaryIcon = "" + secondaryLabel = "" + secondaryHref = "" + secondaryIcon = "" + color = "primary" + variant = "default" + class = "" + } + + view { +
+
+ {#if showBreadcrumbs && breadcrumbs.length > 0} + + {/if} + +
+
+ {#if icon} + + + + {/if} + + + + +
+ +
+ {#if secondaryLabel} +
+
+ + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Pagination.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Pagination.wrn new file mode 100644 index 00000000..afbfc65c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Pagination.wrn @@ -0,0 +1,20 @@ +component Pagination { + props { + @event change = function + @event previous = function + @event next = function + size = "default" + color = "primary" + label = "Pagination" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PinInput.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PinInput.wrn new file mode 100644 index 00000000..8aa45c9e --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PinInput.wrn @@ -0,0 +1,114 @@ +component PinInput { + props { + size = "default" + color = "primary" + label = "Verification code" + name = "pin" + value = "" + length = 4 + pattern = "[0-9]" + type = "text" + inputMode = "numeric" + placeholder = "○" + autocomplete = "one-time-code" + masked = false + disabled = false + readonly = false + required = false + autoFocus = false + autoSubmit = false + allowPaste = true + clearable = true + clearLabel = "Clear code" + separator = "" + groupSize = 0 + helpText = "" + invalid = false + validationMessage = "" + class = "" + @event input = function + @event change = function + @event complete = function + @event paste = function + @event clear = function + @event error = function + } + + functions { + function inputIndexes() { + return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].slice( + 0, + Math.max(1, Math.min(12, Number(length))) + ) + } + } + + view { +
+
+ {label} + +
+ +
+ {#each inputIndexes() as index} + + {#if separator && groupSize !== 0 && (index + 1) % groupSize === 0 && index + 1 !== length} + + {/if} + {/each} +
+ + + + {#if helpText && !validationMessage}{helpText}{/if} + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Popover.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Popover.wrn new file mode 100644 index 00000000..2b196a00 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Popover.wrn @@ -0,0 +1,21 @@ +component Popover { + props { + @event open = function + @event close = function + size = "default" + color = "primary" + title = "Popover" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { +
+
{title}
+ {#if description}

{description}

{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PortalDashboard.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PortalDashboard.wrn new file mode 100644 index 00000000..e8001518 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PortalDashboard.wrn @@ -0,0 +1,98 @@ +component PortalDashboard { + props { + @event action = function + @event navigate = function + size = "default" + color = "primary" + eyebrow = "Overview" + eyebrowKey = "" + title = "Dashboard" + titleKey = "" + description = "" + descriptionKey = "" + userName = "" + metrics = [] + actions = [] + updates = [] + tasks = [] + class = "" + } + + functions { + function chooseAction(item, index) { + $emit("action", { item: item, value: item.value || "", index: index }) + } + + function chooseNavigation(item, index) { + $emit("navigate", { item: item, value: item.value || "", index: index }) + } + } + + view { +
+
+
+ {#if eyebrowKey}{eyebrow}{/if} + {#if !eyebrowKey}{eyebrow}{/if} +

+ {#if titleKey}{title}{/if} + {#if !titleKey}{title}{/if} + {#if userName}, {userName}{/if} +

+ {#if descriptionKey}

{description}

{/if} + {#if !descriptionKey && description}

{description}

{/if} +
+
+
+ +
+ {#each metrics as item} +
+ +
{item.label}{item.value}{#if item.detail}{item.detail}{/if}
+
+ {/each} +
+ +
+
+
Shortcuts

Quick actions

+
+ {#each actions as item, index} + + + {item.label}{#if item.description}{item.description}{/if} + + + {/each} +
+
+ +
+
Priority

Tasks requiring attention

+ +
+ +
+
Latest

Recent updates

+
+ {#each updates as item} +
+ +
{item.label}{#if item.detail}

{item.detail}

{/if}{item.time || ''}
+
+ {/each} +
+
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PreferenceSwitcher.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PreferenceSwitcher.wrn new file mode 100644 index 00000000..29962022 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PreferenceSwitcher.wrn @@ -0,0 +1,82 @@ +component PreferenceSwitcher { + props { + @event theme = function + @event color = function + @event language = function + size = "default" + color = "primary" + themeLabel = "Theme" + colorLabel = "Accent color" + languageLabel = "Language" + languages = [ + {"label": "English", "shortLabel": "EN", "value": "en"}, + {"label": "हिन्दी", "shortLabel": "हि", "value": "hi"}, + {"label": "मराठी", "shortLabel": "म", "value": "mr"} + ] + colors = [ + {"label": "Blue", "value": "blue", "hex": "#2563eb"}, + {"label": "Cyan", "value": "cyan", "hex": "#0891b2"}, + {"label": "Emerald", "value": "emerald", "hex": "#059669"}, + {"label": "Violet", "value": "violet", "hex": "#7c3aed"}, + {"label": "Rose", "value": "rose", "hex": "#e11d48"}, + {"label": "Amber", "value": "amber", "hex": "#d97706"} + ] + compact = true + class = "" + } + + functions { + function choose(type, value) { + $emit(type, { value: value }) + } + } + + view { +
+
+ + + {#if !compact}{themeLabel}{/if} + +
+ {themeLabel} +
+ + +
+
+
+ +
+ + + {#if !compact}{colorLabel}{/if} + +
+ {colorLabel} +
+ {#each colors as item} + + {/each} +
+
+
+ +
+ + + + {#if !compact}{languageLabel}{/if} + +
+ {languageLabel} + {#each languages as item} + + {/each} +
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PublicPageShell.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PublicPageShell.wrn new file mode 100644 index 00000000..e98f9c02 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/PublicPageShell.wrn @@ -0,0 +1,53 @@ +component PublicPageShell { + props { + maxWidth = "full" + fullWidth = true + headerOffset = "none" + background = "default" + overflow = "clip" + minHeight = "screen" + size = "default" + color = "primary" + variant = "default" + class = "" + } + + view { +
+ + + {#if fullWidth} +
+ +
+ {:else} +
+ +
+ {/if} + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Radio.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Radio.wrn new file mode 100644 index 00000000..1da0c2a8 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Radio.wrn @@ -0,0 +1,56 @@ +component Radio { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Radio" + hiddenLabel = false + placeholder = "" + variant = "normal" + icon = "" + iconPosition = "start" + value = "on" + options = [] + checked = false + orientation = "vertical" + card = false + rightAligned = false + list = false + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { checked: sourceEvent.currentTarget.checked, value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
{#if options.length || cornerHint}{label}{#if cornerHint}{cornerHint}{/if}{/if}
+ {#if options.length} +
+ {#each options as option} + + {/each} +
+ {:else} + + {/if} + {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/RangeSlider.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/RangeSlider.wrn new file mode 100644 index 00000000..f501e7bb --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/RangeSlider.wrn @@ -0,0 +1,68 @@ +component RangeSlider { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Range" + hiddenLabel = false + placeholder = "" + variant = "normal" + icon = "" + iconPosition = "start" + value = 50 + min = 0 + max = 100 + step = 1 + showValue = true + showBounds = true + showSteps = false + marks = [] + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + state currentValue = value + functions { + function percent() { if (Number(max) === Number(min)) { return 0 } return (Number(currentValue) - Number(min)) / (Number(max) - Number(min)) * 100 } + function setValue(nextValue, sourceEvent, commit, detail, root, slider, input, output, progressValue) { if (readonly || disabled) { return } currentValue = Number(nextValue); root = sourceEvent.currentTarget.closest(".wire-next--range-slider"); if (root) { slider = root.querySelector("[role=slider]"); input = root.querySelector("input[name='" + name + "']"); output = root.querySelector("output"); progressValue = (currentValue - Number(min)) / (Number(max) - Number(min)) * 100; if (slider) { slider.setAttribute("aria-valuenow", String(currentValue)); slider.style.setProperty("--wire-range-progress", progressValue + "%") } if (input) { input.value = String(currentValue) } if (output) { output.textContent = String(currentValue) } } detail = { value: currentValue, min: min, max: max, step: step, name: name, sourceEvent: sourceEvent }; $emit("input", detail); if (commit) { $emit("change", detail) } } + function valueFromPointer(sourceEvent, rect, ratio) { rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); return Number(min) + ratio * (Number(max) - Number(min)) } + function beginSlide(sourceEvent, rect, ratio, rawValue) { if (readonly || disabled) { return } sourceEvent.currentTarget.setPointerCapture(sourceEvent.pointerId); rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function moveSlide(sourceEvent, rect, ratio, rawValue) { if (!sourceEvent.currentTarget.hasPointerCapture(sourceEvent.pointerId)) { return } rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function endSlide(sourceEvent, rect, ratio, rawValue) { rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); if (sourceEvent.currentTarget.hasPointerCapture(sourceEvent.pointerId)) { sourceEvent.currentTarget.releasePointerCapture(sourceEvent.pointerId) } $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function selectMark(sourceEvent, root, slider, input, output, nextValue, progressValue, detail) { if (readonly || disabled) { return } root = sourceEvent.currentTarget.closest(".wire-next--range-slider"); slider = root.querySelector(".wire-next__custom-slider"); input = root.querySelector(".wire-next__range-value"); output = root.querySelector("output"); nextValue = Number(sourceEvent.currentTarget.dataset.value); currentValue = nextValue; progressValue = (nextValue - Number(min)) / (Number(max) - Number(min)) * 100; slider.setAttribute("aria-valuenow", String(nextValue)); slider.style.setProperty("--wire-range-progress", progressValue + "%"); input.setAttribute("value", String(nextValue)); output.replaceChildren(String(nextValue)); detail = { value: nextValue, min: min, max: max, step: step, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function handleKey(sourceEvent) { if (sourceEvent.key === "ArrowRight") { sourceEvent.preventDefault(); currentValue = Math.min(Number(max), Number(currentValue) + Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "ArrowLeft") { sourceEvent.preventDefault(); currentValue = Math.max(Number(min), Number(currentValue) - Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "Home") { sourceEvent.preventDefault(); currentValue = Number(min); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "End") { sourceEvent.preventDefault(); currentValue = Number(max); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } } + function emitFocus(nameEvent, sourceEvent) { $emit(nameEvent, { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function decreaseValue(sourceEvent) { currentValue = Math.max(Number(min), Number(currentValue) - Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function increaseValue(sourceEvent) { currentValue = Math.min(Number(max), Number(currentValue) + Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if icon}{/if} + +
+ +
+ + {#if marks.length}{#each marks as mark}{/each}{/if} +
+ {#if showBounds}
{min}Step {step}{max}
{/if} +
+ {#if showValue}{currentValue}{/if} + +
+ {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Rating.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Rating.wrn new file mode 100644 index 00000000..a92de2af --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Rating.wrn @@ -0,0 +1,21 @@ +component Rating { + props { + @event input = function + @event change = function + size = "default" + color = "primary" + title = "Rating" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Scrollspy.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Scrollspy.wrn new file mode 100644 index 00000000..305d2d72 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Scrollspy.wrn @@ -0,0 +1,18 @@ +component Scrollspy { + props { + @event change = function + size = "default" + color = "primary" + label = "Scrollspy" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/SearchBox.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/SearchBox.wrn new file mode 100644 index 00000000..bcb7243a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/SearchBox.wrn @@ -0,0 +1,80 @@ +component SearchBox { + props { + size = "default" + color = "primary" + label = "Search Box" + name = "" + value = "" + placeholder = "" + type = "search" + min = "" + max = "" + step = "" + disabled = false + required = false + class = "" + } + + state query = value + + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Section.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Section.wrn new file mode 100644 index 00000000..c0e65c22 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Section.wrn @@ -0,0 +1,60 @@ +component Section { + props { + id = "" + size = "default" + color = "primary" + variant = "default" + spacing = "lg" + maxWidth = "xl" + fullWidth = false + borderTop = false + borderBottom = false + class = "" + } + + view { +
+ {#if fullWidth} + + {:else} + + + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/SectionHeader.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/SectionHeader.wrn new file mode 100644 index 00000000..a70c54fb --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/SectionHeader.wrn @@ -0,0 +1,113 @@ +component SectionHeader { + props { + id = "" + eyebrow = "" + title = "" + description = "" + align = "left" + size = "default" + color = "primary" + headingLevel = 2 + maxWidth = "3xl" + class = "" + } + + view { +
+
+
+ + + {#if eyebrow} +

+ {eyebrow} +

+ {/if} +
+ + {#if headingLevel === 1} +

+ {title} +

+ {:else if headingLevel === 3} +

+ {title} +

+ {:else} +

+ {title} +

+ {/if} + + {#if description} +

+ {description} +

+ {/if} + + +
+ +
+ +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Select.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Select.wrn new file mode 100644 index 00000000..23c13a94 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Select.wrn @@ -0,0 +1,61 @@ +component Select { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event open = function + @event close = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Select" + hiddenLabel = false + value = "" + values = [] + options = [] + placeholder = "Select an option" + variant = "normal" + icon = "" + iconPosition = "start" + helperText = "" + cornerHint = "" + error = "" + inline = false + multiple = false + readonly = false + disabled = false + required = false + class = "" + } + functions { + function selected(option) { + if (multiple) return values.includes(option.value) + return option.value === value + } + function emitField(nameEvent, sourceEvent) { + sourceEvent.stopPropagation() + $emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) + } + function handleFocus(sourceEvent) { emitField("focus", sourceEvent); $emit("open", { name: name, sourceEvent: sourceEvent }) } + function handleBlur(sourceEvent) { emitField("blur", sourceEvent); $emit("close", { name: name, sourceEvent: sourceEvent }) } + function handleInvalid(sourceEvent) { $emit("invalid", { name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if icon}{/if} + + {#if variant === "floating"}{label}{/if} +
+ {#if helperText}{helperText}{/if} + {error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Sidebar.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Sidebar.wrn new file mode 100644 index 00000000..7e64904a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Sidebar.wrn @@ -0,0 +1,79 @@ +component Sidebar { + props { + @event toggle = function + @event open = function + @event close = function + @event select = function + size = "default" + color = "primary" + label = "Sidebar" + items = [] + active = "" + orientation = "horizontal" + mobileLabel = "Open navigation" + class = "" + } + + state mobileOpen = false + + functions { + function toggleSidebar() { + mobileOpen = !mobileOpen + $emit("toggle", { open: mobileOpen }) + $emit(mobileOpen ? "open" : "close", { source: "mobile" }) + } + + function closeSidebar() { + mobileOpen = false + $emit("close", { source: "mobile" }) + } + + function selectItem(item, level) { + mobileOpen = false + $emit("select", { item: item, value: item.value || "", level: level }) + } + } + + view { +
+ + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/SplitHero.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/SplitHero.wrn new file mode 100644 index 00000000..cd523eb1 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/SplitHero.wrn @@ -0,0 +1,98 @@ +component SplitHero { + props { + eyebrow = "" + title = "A better digital experience" + highlight = "" + description = "" + primaryLabel = "" + primaryHref = "" + primaryIcon = "" + secondaryLabel = "" + secondaryHref = "" + secondaryIcon = "" + visualPosition = "right" + reverse = false + ratio = "balanced" + size = "default" + color = "primary" + variant = "default" + trustItems = [] + class = "" + } + + view { +
+
+
+ {#if eyebrow} +
+ + {eyebrow} +
+ {/if} + +

+ {title} + {#if highlight} + {highlight} + {/if} +

+ + {#if description} +

{description}

+ {/if} + + + + + + {#if trustItems.length > 0} +
+ {#each trustItems as item} + + + {item.label || item.title || item} + + {/each} +
+ {/if} + + + +
+ +
+ + +
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/StatsBar.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/StatsBar.wrn new file mode 100644 index 00000000..46cb04e9 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/StatsBar.wrn @@ -0,0 +1,40 @@ +component StatsBar { + props { + items = [] + columns = 4 + compact = true + dividers = true + icons = true + size = "default" + color = "primary" + variant = "raised" + maxWidth = "xl" + class = "" + } + + view { +
+
+ +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Stepper.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Stepper.wrn new file mode 100644 index 00000000..725ab1c2 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Stepper.wrn @@ -0,0 +1,21 @@ +component Stepper { + props { + @event change = function + @event previous = function + @event next = function + @event complete = function + size = "default" + color = "primary" + label = "Stepper" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/StrongPassword.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/StrongPassword.wrn new file mode 100644 index 00000000..d8f3137d --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/StrongPassword.wrn @@ -0,0 +1,215 @@ +component StrongPassword { + props { + size = "default" + color = "primary" + label = "Password" + name = "password" + value = "" + placeholder = "Create a strong password" + autocomplete = "new-password" + minLength = 8 + specialCharactersSet = "!@#$%^&*()_+-=[]{}|;:,.<>?" + requireLowercase = true + requireUppercase = true + requireNumber = true + requireSpecialCharacter = true + showRequirements = true + presentation = "inline" + hintText = "Use a unique password you do not use elsewhere." + emptyLabel = "Enter a password" + weakLabel = "Weak" + fairLabel = "Fair" + goodLabel = "Good" + strongLabel = "Strong" + disabled = false + readonly = false + required = false + invalid = false + validationMessage = "" + class = "" + @event input = function + @event change = function + @event strength = function + } + + state password = value + state detailsOpen = false + + functions { + function hasMinimumLength() { + return password.length >= Number(minLength) + } + + function hasLowercase() { + return password !== password.toUpperCase() + } + + function hasUppercase() { + return password !== password.toLowerCase() + } + + function hasNumber() { + return containsCharacterAt("0123456789", 0) + } + + function hasSpecialCharacter() { + return containsCharacterAt(specialCharactersSet, 0) + } + + function containsCharacterAt(characters, index) { + if (index >= characters.length) { + return false + } + if (password.includes(characters[index])) { + return true + } + return containsCharacterAt(characters, index + 1) + } + + function score() { + return (hasMinimumLength() ? 1 : 0) + (requireLowercase && hasLowercase() ? 1 : 0) + (requireUppercase && hasUppercase() ? 1 : 0) + (requireNumber && hasNumber() ? 1 : 0) + (requireSpecialCharacter && hasSpecialCharacter() ? 1 : 0) + } + + function maximumScore() { + return 1 + (requireLowercase ? 1 : 0) + (requireUppercase ? 1 : 0) + (requireNumber ? 1 : 0) + (requireSpecialCharacter ? 1 : 0) + } + + function strengthPercent() { + return Math.round(score() / maximumScore() * 100) + } + + function strengthLevel() { + if (!password) { + return "empty" + } + if (strengthPercent() <= 25) { + return "weak" + } + if (strengthPercent() <= 50) { + return "fair" + } + if (strengthPercent() < 100) { + return "good" + } + return "strong" + } + + function strengthLabel() { + if (strengthLevel() === "weak") { + return weakLabel + } + if (strengthLevel() === "fair") { + return fairLabel + } + if (strengthLevel() === "good") { + return goodLabel + } + if (strengthLevel() === "strong") { + return strongLabel + } + return emptyLabel + } + + } + + view { +
+ +
+ + + {#if presentation === "popover"} +
+ +
+
+ Password strength + {password ? strengthLabel() : emptyLabel} +
+
+ +
+ {#if showRequirements} +
    +
  • + At least {minLength} characters +
  • + {#if requireLowercase}
  • One lowercase letter
  • {/if} + {#if requireUppercase}
  • One uppercase letter
  • {/if} + {#if requireNumber}
  • One number
  • {/if} + {#if requireSpecialCharacter}
  • One special character: {specialCharactersSet}
  • {/if} +
+ {/if} + {#if hintText}{hintText}{/if} +
+
+ {/if} +
+ + {#if presentation !== "popover"} +
+
+ Password strength + {password ? strengthLabel() : emptyLabel} +
+
+ +
+ {#if showRequirements} +
    +
  • At least {minLength} characters
  • + {#if requireLowercase}
  • One lowercase letter
  • {/if} + {#if requireUppercase}
  • One uppercase letter
  • {/if} + {#if requireNumber}
  • One number
  • {/if} + {#if requireSpecialCharacter}
  • One special character: {specialCharactersSet}
  • {/if} +
+ {/if} + {#if hintText}{hintText}{/if} +
+ {/if} + + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/StyledIcon.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/StyledIcon.wrn new file mode 100644 index 00000000..a394af25 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/StyledIcon.wrn @@ -0,0 +1,19 @@ +component StyledIcon { + props { + size = "default" + color = "primary" + title = "Styled Icon" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Switch.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Switch.wrn new file mode 100644 index 00000000..478a92fe --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Switch.wrn @@ -0,0 +1,39 @@ +component Switch { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Switch" + hiddenLabel = false + placeholder = "" + variant = "normal" + icon = "" + iconPosition = "start" + value = "on" + checked = false + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { checked: sourceEvent.currentTarget.checked, value: value, name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
{#if cornerHint}{label}{cornerHint}{/if}
+ + {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Tabs.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Tabs.wrn new file mode 100644 index 00000000..e8d747c4 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Tabs.wrn @@ -0,0 +1,90 @@ +component Tabs { + props { + size = "default" + color = "primary" + label = "Tabs" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + + state activeValue = active || (items[0] ? (items[0].value || items[0].id || "0") : "") + + view { +
+
+ {#each items as item, index} + + {/each} +
+ +
+ {#each items as item, index} +
+ {#if item.title && item.title !== item.label} +

{item.title}

+ {/if} + {#if item.description} +

{item.description}

+ {/if} + {#if item.content} +
{item.content}
+ {/if} +
+ {/each} + + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/TextLink.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/TextLink.wrn new file mode 100644 index 00000000..a490e020 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/TextLink.wrn @@ -0,0 +1,87 @@ +component TextLink { + props { + @event click = function + @event focus = function + @event blur = function + label = "Learn more" + href = "#" + target = "" + rel = "" + external = false + icon = "" + iconPosition = "start" + showArrow = true + underline = false + size = "default" + color = "primary" + variant = "default" + disabled = false + class = "" + } + + view { + + {#if disabled} + + {#if icon && iconPosition === "start"} + + {/if} + {label} + + {:else} + + {#if icon && iconPosition === "start"} + + {/if} + + {label} + + {#if icon && iconPosition === "end"} + + {/if} + + {#if external} + + {:else if showArrow} + + {/if} + + {/if} + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Textarea.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Textarea.wrn new file mode 100644 index 00000000..98cfc33f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Textarea.wrn @@ -0,0 +1,53 @@ +component Textarea { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Textarea" + hiddenLabel = false + placeholder = "" + value = "" + variant = "normal" + icon = "" + iconPosition = "start" + helperText = "" + cornerHint = "" + error = "" + inline = false + rows = 5 + resize = "vertical" + readonly = false + disabled = false + required = false + minlength = "" + maxlength = "" + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { + sourceEvent.stopPropagation() + $emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) + } + function handleInvalid(sourceEvent) { + $emit("invalid", { value: sourceEvent.currentTarget.value, name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) + } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if icon}{/if} + + {#if variant === "floating"}{label}{/if} +
+ {#if helperText}{helperText}{/if} + {error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/TimePicker.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/TimePicker.wrn new file mode 100644 index 00000000..64398d44 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/TimePicker.wrn @@ -0,0 +1,63 @@ +component TimePicker { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event open = function + @event close = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Time" + hiddenLabel = false + value = "" + placeholder = "" + variant = "normal" + icon = "icon-[lucide--clock-3]" + iconPosition = "end" + helperText = "" + cornerHint = "" + error = "" + inline = false + min = "" + max = "" + step = "" + format = "24" + minuteStep = 5 + hours = ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"] + minutes = ["00", "05", "10", "15", "20", "25", "30", "35", "40", "45", "50", "55"] + readonly = false + disabled = false + required = false + class = "" + } + state currentValue = value + state selectedHour = value ? value.split(":")[0] : "00" + state selectedMinute = value ? value.split(":")[1] : "00" + state expanded = false + functions { + function commit(part, nextValue, sourceEvent, next, detail) { if (part === "hour") { selectedHour = String(nextValue).padStart(2, "0") } if (part === "minute") { selectedMinute = String(nextValue).padStart(2, "0") } next = selectedHour + ":" + selectedMinute; if ((min && next < min) || (max && next > max)) { return } currentValue = next; detail = { value: currentValue, hour: selectedHour, minute: selectedMinute, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function selectTimePart(sourceEvent, root, input, parts, hourValue, minuteValue, next, trigger, detail) { root = sourceEvent.currentTarget.closest(".wire-next--time-picker"); input = root.querySelector(".wire-next__time-value"); parts = String(input.value || value || "00:00").split(":"); hourValue = sourceEvent.currentTarget.dataset.part === "hour" ? sourceEvent.currentTarget.dataset.value : parts[0]; minuteValue = sourceEvent.currentTarget.dataset.part === "minute" ? sourceEvent.currentTarget.dataset.value : parts[1]; next = hourValue + ":" + minuteValue; if ((min && next < min) || (max && next > max)) { return } currentValue = next; input.setAttribute("value", next); trigger = root.querySelector(".wire-next__time-trigger span"); if (trigger) { trigger.replaceChildren(next) } sourceEvent.currentTarget.setAttribute("aria-pressed", "true"); detail = { value: next, hour: hourValue, minute: minuteValue, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function openPicker(sourceEvent) { expanded = true; $emit("open", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function closePicker(sourceEvent) { expanded = false; $emit("close", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleFocus(sourceEvent) { $emit("focus", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleBlur(sourceEvent) { $emit("blur", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleInvalid(sourceEvent) { $emit("invalid", { name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if icon}{/if} + + +
+ + {#if helperText}{helperText}{/if} + {error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Timeline.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Timeline.wrn new file mode 100644 index 00000000..3d3d35dd --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Timeline.wrn @@ -0,0 +1,83 @@ +component Timeline { + props { + size = "default" + color = "primary" + title = "Timeline" + description = "" + items = [] + variant = "default" + class = "" + } + + view { +
+ {#if title || description} +
+ {#if title} +

{title}

+ {/if} + {#if description} +

{description}

+ {/if} +
+ {/if} + +
    + {#each items as item, index} +
  1. + + + + +
    +
    +
    +

    {item.title || item.label}

    + {#if item.subtitle} +

    {item.subtitle}

    + {/if} +
    + {#if item.date || item.meta} + + {/if} +
    + + {#if item.description} +

    {item.description}

    + {/if} + + {#if item.href} + + {item.actionLabel || "View details"} + + + {/if} +
    +
  2. + {:empty} +
  3. No timeline items available.
  4. + {/each} +
+ + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Toast.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Toast.wrn new file mode 100644 index 00000000..bda42b49 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Toast.wrn @@ -0,0 +1,21 @@ +component Toast { + props { + @event dismiss = function + @event action = function + size = "default" + color = "primary" + title = "Toast" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ToastNotifications.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ToastNotifications.wrn new file mode 100644 index 00000000..d49d5547 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ToastNotifications.wrn @@ -0,0 +1,23 @@ +component ToastNotifications { + props { + @event add = function + @event dismiss = function + @event clear = function + @event action = function + size = "default" + color = "primary" + title = "Toast Notifications" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ToggleCount.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ToggleCount.wrn new file mode 100644 index 00000000..0a858af9 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ToggleCount.wrn @@ -0,0 +1,237 @@ +component ToggleCount { + props { + size = "default" + color = "primary" + variant = "segmented" + class = "" + + name = "billing-cycle" + value = "monthly" + firstValue = "monthly" + firstLabel = "Monthly" + secondValue = "annual" + secondLabel = "Annual" + ariaLabel = "Billing frequency" + + items = [] + currency = "$" + suffix = "" + firstValueKey = "monthly" + secondValueKey = "annual" + emptyValue = "—" + + align = "end" + fullWidth = true + disabled = false + animate = true + animationDuration = 450 + animationSteps = 18 + + @event change = function + @event toggle = function + } + + state selectedValue = value + + functions { + function isFirstSelected() { + return selectedValue === firstValue + } + + function isSecondSelected() { + return selectedValue === secondValue + } + + function displayValue(item) { + if (isSecondSelected()) { + return item[secondValueKey] !== undefined + ? item[secondValueKey] + : emptyValue + } + + return item[firstValueKey] !== undefined + ? item[firstValueKey] + : emptyValue + } + + function dispatchToggleEvent(sourceEvent, previousValue, root, customEvent) { + root = sourceEvent.currentTarget.closest("[data-wrn-toggle-count]") + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("change", true, false, { + component: "ToggleCount", + name: name, + value: selectedValue, + previousValue: previousValue, + firstValue: firstValue, + secondValue: secondValue + }) + root.dispatchEvent(customEvent) + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("toggle", true, false, { + component: "ToggleCount", + name: name, + value: selectedValue, + previousValue: previousValue, + firstValue: firstValue, + secondValue: secondValue + }) + root.dispatchEvent(customEvent) + } + + function selectValue(sourceEvent, nextValue, previousValue) { + if (disabled || selectedValue === nextValue) { + return + } + + previousValue = selectedValue + selectedValue = nextValue + + if ( + animate && + !window.matchMedia("(prefers-reduced-motion: reduce)").matches + ) { + animateDisplayedValues(sourceEvent, previousValue) + } + + dispatchToggleEvent(sourceEvent, previousValue) + } + + function animateDisplayedValues(sourceEvent, previousValue, root, nodes) { + root = sourceEvent.currentTarget.closest("[data-wrn-toggle-count]") + + if (!root) { + return + } + + nodes = root.querySelectorAll("[data-toggle-count-value]") + animateValueAt(nodes, 0, previousValue) + } + + function animateValueAt(nodes, index, previousValue, node, fromValue, toValue) { + if (index >= nodes.length) { + return + } + + node = nodes[index] + fromValue = Number( + previousValue === secondValue + ? node.getAttribute("data-second-value") + : node.getAttribute("data-first-value") + ) + toValue = Number( + selectedValue === secondValue + ? node.getAttribute("data-second-value") + : node.getAttribute("data-first-value") + ) + + if (!Number.isNaN(fromValue) && !Number.isNaN(toValue)) { + animateValueFrame(node, fromValue, toValue, 0) + } + + animateValueAt(nodes, index + 1, previousValue) + } + + function animateValueFrame(node, fromValue, toValue, frame, totalFrames, nextValue) { + totalFrames = Math.max(1, Number(animationSteps) || 1) + + if (frame >= totalFrames) { + node.replaceChildren(String(toValue)) + return + } + + nextValue = Math.round( + fromValue + + (toValue - fromValue) * (frame / totalFrames) + ) + node.replaceChildren(String(nextValue)) + + setTimeout( + animateValueFrame, + Math.max(1, Number(animationDuration) / totalFrames), + node, + fromValue, + toValue, + frame + 1 + ) + } + + function toggleValue(sourceEvent) { + selectValue( + sourceEvent, + isFirstSelected() ? secondValue : firstValue + ) + } + } + + view { +
+ + +
+ {#if variant === "switch"} + {firstLabel} + + {secondLabel} + {:else} +
+ + +
+ {/if} +
+ + {#if items.length > 0} +
+ {#each items as item} +
+ {item.label || item.name} + + {#if currency}{currency}{/if} + {displayValue(item)} + {#if suffix}{suffix}{/if} + + {#if item.description}{item.description}{/if} +
+ {/each} +
+ {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/TogglePassword.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/TogglePassword.wrn new file mode 100644 index 00000000..43eb9cc6 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/TogglePassword.wrn @@ -0,0 +1,153 @@ +component TogglePassword { + props { + size = "default" + color = "primary" + label = "Password" + name = "password" + value = "" + placeholder = "Enter your password" + autocomplete = "current-password" + minlength = "" + maxlength = "" + pattern = "(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}" + fields = [] + visible = false + toggleable = true + toggleMode = "button" + checkboxLabel = "Show password" + showLabel = "Show password" + hideLabel = "Hide password" + disabled = false + readonly = false + required = false + invalid = false + helpText = "" + validationMessage = "" + class = "" + @event input = function + @event change = function + @event toggle = function + } + + state revealed = visible + + functions { + function toggleVisibility() { + if (disabled || readonly || !toggleable) { + return + } + revealed = !revealed + } + + function fieldId(field, index) { + return field.id || field.name || name + "-" + index + } + + function fieldName(field, index) { + return field.name || name + "-" + index + } + } + + view { +
+ {#if fields.length} +
+ {#each fields as field, index} +
+ +
+ + {#if toggleable && toggleMode === "button"} + + {/if} +
+
+ {/each} +
+ {:else} + +
+ + {#if toggleable && toggleMode === "button"} + + {/if} +
+ {/if} + {#if toggleable && toggleMode === "checkbox"} + + {/if} + {#if helpText && !validationMessage}{helpText}{/if} + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/TreeView.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/TreeView.wrn new file mode 100644 index 00000000..d04a730b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/TreeView.wrn @@ -0,0 +1,23 @@ +component TreeView { + props { + @event select = function + @event toggle = function + @event expand = function + @event collapse = function + size = "default" + color = "primary" + title = "Tree View" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Typography.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Typography.wrn new file mode 100644 index 00000000..d7d36173 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/Typography.wrn @@ -0,0 +1,75 @@ +component Typography { + props { + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + + view { +
+ +
+ } + + style { + .wire-typography :where(h1, h2, h3, h4) { + color: var(--wire-color-text); + font-weight: 700; + letter-spacing: -0.02em; + line-height: 1.2; + break-after: avoid; + } + + .wire-typography :where(h1) { font-size: clamp(2rem, 4vw, 3.5rem); margin: 0 0 1.5rem; } + .wire-typography :where(h2) { font-size: clamp(1.5rem, 3vw, 2.25rem); margin: 2.5rem 0 1rem; } + .wire-typography :where(h3) { font-size: 1.35rem; margin: 2rem 0 0.75rem; } + .wire-typography :where(p, ul, ol, blockquote, pre, table) { margin: 1rem 0; } + .wire-typography :where(p, li) { color: var(--wire-color-text-muted); line-height: 1.8; } + .wire-typography :where(a) { color: var(--wire-color-primary); font-weight: 600; text-underline-offset: 0.2em; } + .wire-typography :where(a:hover) { color: var(--wire-color-primary-hover); text-decoration: underline; } + .wire-typography :where(ul, ol) { padding-left: 1.4rem; } + .wire-typography :where(ul) { list-style: disc; } + .wire-typography :where(ol) { list-style: decimal; } + .wire-typography :where(blockquote) { + border-left: 4px solid var(--wire-color-primary); + background: var(--wire-color-primary-soft); + border-radius: 0 0.75rem 0.75rem 0; + padding: 1rem 1.25rem; + color: var(--wire-color-text); + } + .wire-typography :where(code) { + border-radius: 0.35rem; + background: var(--wire-color-surface-soft); + padding: 0.15rem 0.35rem; + font-size: 0.9em; + } + .wire-typography :where(pre) { + overflow-x: auto; + border: 1px solid var(--wire-color-border); + border-radius: 1rem; + background: var(--wire-color-surface-raised); + padding: 1rem; + } + .wire-typography :where(img) { border-radius: 1rem; } + .wire-typography :where(hr) { border-color: var(--wire-color-border); margin: 2rem 0; } + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/WysiwygEditor.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/WysiwygEditor.wrn new file mode 100644 index 00000000..dfb91935 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/WysiwygEditor.wrn @@ -0,0 +1,23 @@ +component WysiwygEditor { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + title = "Wysiwyg Editor" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/alert.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/alert.wrn new file mode 100644 index 00000000..ba2e904b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/alert.wrn @@ -0,0 +1,142 @@ +component Alert { + props { + size = "default" + color = "info" + variant = "soft" + class = "" + radius = "md" + shadow = "sm" + + title = "Alert" + description = "" + items = [] + actions = [] + + showIcon = false + icon = "" + dismissible = false + dismissLabel = "Dismiss alert" + role = "alert" + live = "polite" + + linkLabel = "" + linkHref = "" + actionLabel = "" + actionHref = "" + compact = false + + @event dismiss = function + @event action = function + } + + state visible = true + + functions { + function dispatchAlertEvent(sourceEvent, eventName, action, root, customEvent) { + root = sourceEvent.currentTarget.closest("[data-wrn-alert]") + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent(eventName, true, false, { + component: "Alert", + title: title, + color: color, + variant: variant, + action: action + }) + root.dispatchEvent(customEvent) + } + + function dismissAlert(sourceEvent) { + visible = false + dispatchAlertEvent(sourceEvent, "dismiss", null) + } + + function selectAction(sourceEvent, action) { + dispatchAlertEvent(sourceEvent, "action", action) + } + } + + view { +
+ {#if showIcon} + + {/if} + +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + + {#if items.length > 0} +
    + {#each items as item}
  • {item.label || item}
  • {/each} +
+ {/if} + + {#if actions.length > 0 || actionLabel || linkLabel} +
+ {#each actions as item} + {item.label} + {/each} + {#if actionLabel} + {actionLabel} + {/if} + {#if linkLabel} + {linkLabel} + {/if} +
+ {/if} +
+ + {#if dismissible} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/avatar.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/avatar.wrn new file mode 100644 index 00000000..1c90e813 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/avatar.wrn @@ -0,0 +1,87 @@ +component Avatar { + props { + @event load = function + @event error = function + @event click = function + src = "" + alt = "" + initials = "" + size = "md" + color = "primary" + variant = "solid" + shape = "circle" + + status = "" + statusLabel = "" + statusPosition = "bottom" + + badge = "" + badgeIcon = "" + badgeLabel = "" + + tooltip = "" + name = "" + description = "" + loading = "lazy" + class = "" + } + + view { + + + + {#if src} + {alt || name} + {:else if initials} + + {:else} + + {/if} + + + {#if status} + + {/if} + + {#if badgeIcon} + + + + {:else if badge} + + {badge} + + {/if} + + {#if tooltip} + {tooltip} + {/if} + + + {#if description} + + {name || alt || initials} + {description} + + {/if} + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/button.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/button.wrn new file mode 100644 index 00000000..34bf88b4 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/button.wrn @@ -0,0 +1,164 @@ +component Button { + props { + @event click = function + @event focus = function + @event blur = function + label = "Button" + loadingLabel = "Loading…" + description = "" + as = "" + href = "" + target = "" + rel = "" + type = "button" + variant = "default" + color = "primary" + size = "default" + disabled = false + loading = false + pill = false + fullWidth = false + icon = "" + iconPosition = "start" + ariaLabel = "" + ariaPressed = "" + ariaExpanded = "" + ariaControls = "" + title = "" + autofocus = false + controlClass = "" + class = "" + } + + view { + + {#if as === "a" || (as === "" && href)} + + {#if loading} + + {/if} + {#if icon && !loading && iconPosition === "start"} + + {/if} + + + {loading ? loadingLabel : label} + + {#if description && !loading} + + {description} + + {/if} + + {#if icon && !loading && iconPosition === "end"} + + {/if} + {#if (size === "icon" || size === "icon-xs" || size === "icon-sm" || size === "icon-lg") && (ariaLabel || label)} + + {/if} + + {:else} + + {/if} + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/carousel.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/carousel.wrn new file mode 100644 index 00000000..4efdb206 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/carousel.wrn @@ -0,0 +1,461 @@ +// Interactive, hydration-safe content carousel. +component Carousel { + props { + @event initialize = function + @event change = function + @event previous = function + @event next = function + @event play = function + @event pause = function + @event reachStart = function + @event reachEnd = function + @event dragStart = function + @event dragEnd = function + size = "default" + color = "primary" + title = "" + description = "" + items = [] + activeIndex = 0 + slidesPerView = 1 + gap = "0.75rem" + showPagination = false + isAutoPlay = false + autoplayInterval = 4000 + isInfiniteLoop = false + isRTL = false + isCentered = false + isDraggable = false + isAutoHeight = false + isSnap = false + showCounter = false + thumbnails = "none" + ariaLabel = "Content carousel" + variant = "default" + class = "" + } + + state currentIndex = activeIndex + state playing = false + state dragOrigin = null + state dragOffset = 0 + state autoplayTimer = null + state carouselRoot = null + + functions { + function slideCount() { + return items.length + } + + function maximumIndex(count, visible) { + count = slideCount() + visible = Math.max(1, Number(slidesPerView) || 1) + if (isCentered || isSnap) { + return Math.max(0, count - 1) + } + return Math.max(0, count - visible) + } + + function normalizedIndex(index, maximum) { + maximum = maximumIndex() + if (slideCount() === 0) { + return 0 + } + if (isInfiniteLoop) { + if (index < 0) { + return maximum + } + if (index > maximum) { + return 0 + } + } + return Math.max(0, Math.min(index, maximum)) + } + + function rememberRoot(sourceEvent, root) { + if (!sourceEvent || !sourceEvent.currentTarget) { + return + } + root = sourceEvent.currentTarget.closest(".wire-next--carousel") + if (root) { + carouselRoot = root + } + } + + function syncNavigation(sourceEvent, index, root, viewport, slides, slide, thumbnails, thumbnail, rail) { + rememberRoot(sourceEvent) + root = carouselRoot + if (!root) { + return + } + if (isSnap) { + viewport = root.querySelector(".wire-next__carousel-viewport") + slides = root.querySelectorAll(".wire-next__carousel-slide") + slide = slides[index] + if (viewport && slide) { + viewport.scrollTo({ + left: slide.offsetLeft - (viewport.clientWidth - slide.clientWidth) / 2, + behavior: "smooth" + }) + } + } + thumbnails = root.querySelectorAll(".wire-next__carousel-thumbnails button") + if (thumbnails[index]) { + thumbnail = thumbnails[index] + rail = thumbnail.parentElement + rail.scrollTo({ + left: thumbnail.offsetLeft - (rail.clientWidth - thumbnail.clientWidth) / 2, + top: thumbnail.offsetTop - (rail.clientHeight - thumbnail.clientHeight) / 2, + behavior: "smooth" + }) + } + } + + function handleSnapScroll(sourceEvent, slides, viewport, viewportCenter, closestIndex, closestDistance, slide, slideCenter, distance, previousIndex) { + if (!isSnap) { + return + } + rememberRoot(sourceEvent) + viewport = sourceEvent.currentTarget + slides = viewport.querySelectorAll(".wire-next__carousel-slide") + viewportCenter = viewport.scrollLeft + viewport.clientWidth / 2 + closestIndex = currentIndex + closestDistance = 1000000000 + slides.forEach(function (candidate, index) { + slideCenter = candidate.offsetLeft + candidate.clientWidth / 2 + distance = Math.abs(slideCenter - viewportCenter) + if (distance < closestDistance) { + closestDistance = distance + closestIndex = index + } + }) + closestIndex = normalizedIndex(closestIndex) + if (closestIndex !== currentIndex) { + previousIndex = currentIndex + currentIndex = closestIndex + $emit("change", { + index: currentIndex, + previousIndex: previousIndex, + item: items[currentIndex], + reason: "snap" + }) + slides = carouselRoot.querySelectorAll(".wire-next__carousel-thumbnails button") + slide = slides[currentIndex] + if (slide) { + viewport = slide.parentElement + viewport.scrollTo({ + left: slide.offsetLeft - (viewport.clientWidth - slide.clientWidth) / 2, + top: slide.offsetTop - (viewport.clientHeight - slide.clientHeight) / 2, + behavior: "smooth" + }) + } + } + } + + function selectSlide(index, reason, sourceEvent, previousIndex) { + if (slideCount() === 0) { + return + } + previousIndex = currentIndex + currentIndex = normalizedIndex(Number(index)) + syncNavigation(sourceEvent, currentIndex) + if (previousIndex === currentIndex && reason !== "initialize") { + return + } + $emit("change", { + index: currentIndex, + previousIndex: previousIndex, + item: items[currentIndex], + reason: reason || "select" + }) + if (currentIndex === 0) { + $emit("reachStart", { index: currentIndex }) + } + if (currentIndex === maximumIndex()) { + $emit("reachEnd", { index: currentIndex }) + } + } + + function previousSlide(sourceEvent, previousIndex) { + previousIndex = currentIndex + selectSlide(currentIndex - 1, "previous", sourceEvent) + $emit("previous", { + index: currentIndex, + previousIndex: previousIndex, + item: items[currentIndex] + }) + } + + function nextSlide(sourceEvent, previousIndex) { + previousIndex = currentIndex + selectSlide(currentIndex + 1, "next", sourceEvent) + $emit("next", { + index: currentIndex, + previousIndex: previousIndex, + item: items[currentIndex] + }) + } + + function handleKeydown(sourceEvent) { + if (sourceEvent.key === "ArrowLeft") { + sourceEvent.preventDefault() + if (isRTL) { + nextSlide(sourceEvent) + } else { + previousSlide(sourceEvent) + } + } + if (sourceEvent.key === "ArrowRight") { + sourceEvent.preventDefault() + if (isRTL) { + previousSlide(sourceEvent) + } else { + nextSlide(sourceEvent) + } + } + if (sourceEvent.key === "Home") { + sourceEvent.preventDefault() + selectSlide(0, "keyboard", sourceEvent) + } + if (sourceEvent.key === "End") { + sourceEvent.preventDefault() + selectSlide(maximumIndex(), "keyboard", sourceEvent) + } + } + + function beginDrag(sourceEvent) { + if (!isDraggable || isSnap) { + return + } + sourceEvent.preventDefault() + dragOrigin = sourceEvent.clientX + dragOffset = 0 + sourceEvent.currentTarget.setPointerCapture(sourceEvent.pointerId) + $emit("dragStart", { index: currentIndex, x: dragOrigin }) + } + + function moveDrag(sourceEvent) { + if (!isDraggable || isSnap || dragOrigin === null) { + return + } + sourceEvent.preventDefault() + dragOffset = sourceEvent.clientX - dragOrigin + } + + function cancelDrag() { + dragOrigin = null + dragOffset = 0 + } + + function endDrag(sourceEvent, distance) { + if (!isDraggable || isSnap || dragOrigin === null) { + return + } + sourceEvent.preventDefault() + distance = dragOffset || sourceEvent.clientX - dragOrigin + dragOrigin = null + dragOffset = 0 + if (Math.abs(distance) > 20) { + if ((distance < 0 && !isRTL) || (distance > 0 && isRTL)) { + nextSlide(sourceEvent) + } else { + previousSlide(sourceEvent) + } + } + $emit("dragEnd", { + index: currentIndex, + distance: distance + }) + } + + function advanceAutoplay() { + if (currentIndex >= maximumIndex()) { + selectSlide(0, "autoplay") + } else { + selectSlide(currentIndex + 1, "autoplay") + } + } + + function startAutoplay() { + if (!isAutoPlay || playing || slideCount() < 2) { + return + } + playing = true + autoplayTimer = setInterval(advanceAutoplay, Math.max(1000, Number(autoplayInterval))) + $emit("play", { index: currentIndex, interval: autoplayInterval }) + } + + function pauseAutoplay() { + if (autoplayTimer) { + clearInterval(autoplayTimer) + } + autoplayTimer = null + if (playing) { + $emit("pause", { index: currentIndex }) + } + playing = false + } + + } + + lifecycle { + mount { + $emit("initialize", { index: currentIndex, count: slideCount() }) + startAutoplay() + } + unmount { + if (autoplayTimer) { + clearInterval(autoplayTimer) + } + } + } + + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/component-catalog.json b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/component-catalog.json new file mode 100644 index 00000000..1b3bfeb3 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/component-catalog.json @@ -0,0 +1,459 @@ +{ + "sourceDocuments": ["Screenshot-directed WRNexus UI catalog reset"], + "components": [ + { + "name": "Container", + "category": "layout", + "purpose": "Theme-aware, responsive container component." + }, + { + "name": "Columns", + "category": "layout", + "purpose": "Theme-aware, responsive columns component." + }, + { + "name": "Grid", + "category": "layout", + "purpose": "Theme-aware, responsive grid component." + }, + { + "name": "LayoutSplitter", + "category": "layout", + "purpose": "Theme-aware, responsive layout splitter component." + }, + { + "name": "Typography", + "category": "layout", + "purpose": "Theme-aware, responsive typography component." + }, + { + "name": "Image", + "category": "layout", + "purpose": "Theme-aware, responsive image component." + }, + { + "name": "Link", + "category": "layout", + "purpose": "Theme-aware, responsive link component." + }, + { + "name": "Divider", + "category": "layout", + "purpose": "Theme-aware, responsive divider component." + }, + { + "name": "Kbd", + "category": "layout", + "purpose": "Theme-aware, responsive kbd component." + }, + { + "name": "CustomScrollbar", + "category": "layout", + "purpose": "Theme-aware, responsive custom scrollbar component." + }, + { + "name": "Accordion", + "category": "base", + "purpose": "Theme-aware, responsive accordion component." + }, + { + "name": "Alert", + "category": "base", + "purpose": "Theme-aware, responsive alert component." + }, + { + "name": "Avatar", + "category": "base", + "purpose": "Theme-aware, responsive avatar component." + }, + { + "name": "AvatarGroup", + "category": "base", + "purpose": "Theme-aware, responsive avatar group component." + }, + { + "name": "Badge", + "category": "base", + "purpose": "Theme-aware, responsive badge component." + }, + { + "name": "Blockquote", + "category": "base", + "purpose": "Theme-aware, responsive blockquote component." + }, + { + "name": "Button", + "category": "base", + "purpose": "Theme-aware, responsive button component." + }, + { + "name": "ButtonGroup", + "category": "base", + "purpose": "Theme-aware, responsive button group component." + }, + { + "name": "Card", + "category": "base", + "purpose": "Theme-aware, responsive card component." + }, + { + "name": "ChatBubble", + "category": "base", + "purpose": "Theme-aware, responsive chat bubble component." + }, + { + "name": "Carousel", + "category": "base", + "purpose": "Theme-aware, responsive carousel component." + }, + { + "name": "Collapse", + "category": "base", + "purpose": "Theme-aware, responsive collapse component." + }, + { + "name": "DatePicker", + "category": "base", + "purpose": "Theme-aware, responsive date picker component." + }, + { + "name": "DeviceFrame", + "category": "base", + "purpose": "Theme-aware, responsive device frame component." + }, + { + "name": "List", + "category": "base", + "purpose": "Theme-aware, responsive list component." + }, + { + "name": "ListGroup", + "category": "base", + "purpose": "Theme-aware, responsive list group component." + }, + { + "name": "LegendIndicator", + "category": "base", + "purpose": "Theme-aware, responsive legend indicator component." + }, + { + "name": "Progress", + "category": "base", + "purpose": "Theme-aware, responsive progress component." + }, + { + "name": "FileUploadProgress", + "category": "base", + "purpose": "Theme-aware, responsive file upload progress component." + }, + { + "name": "Rating", + "category": "base", + "purpose": "Theme-aware, responsive rating component." + }, + { + "name": "Skeleton", + "category": "base", + "purpose": "Theme-aware, responsive skeleton component." + }, + { + "name": "Spinner", + "category": "base", + "purpose": "Theme-aware, responsive spinner component." + }, + { + "name": "StyledIcon", + "category": "base", + "purpose": "Theme-aware, responsive styled icon component." + }, + { + "name": "Toast", + "category": "base", + "purpose": "Theme-aware, responsive toast component." + }, + { + "name": "Timeline", + "category": "base", + "purpose": "Theme-aware, responsive timeline component." + }, + { + "name": "TreeView", + "category": "base", + "purpose": "Theme-aware, responsive tree view component." + }, + { + "name": "Marquee", + "category": "base", + "purpose": "Theme-aware, responsive marquee component." + }, + { + "name": "Navbar", + "category": "navigation", + "purpose": "Theme-aware, responsive navbar component." + }, + { + "name": "Footer", + "category": "navigation", + "purpose": "Responsive application footer with structured links and pre/post content slots." + }, + { + "name": "MegaMenu", + "category": "navigation", + "purpose": "Theme-aware, responsive mega menu component." + }, + { + "name": "Nav", + "category": "navigation", + "purpose": "Theme-aware, responsive nav component." + }, + { + "name": "Tabs", + "category": "navigation", + "purpose": "Theme-aware, responsive tabs component." + }, + { + "name": "Sidebar", + "category": "navigation", + "purpose": "Theme-aware, responsive sidebar component." + }, + { + "name": "Scrollspy", + "category": "navigation", + "purpose": "Theme-aware, responsive scrollspy component." + }, + { + "name": "Breadcrumb", + "category": "navigation", + "purpose": "Theme-aware, responsive breadcrumb component." + }, + { + "name": "Pagination", + "category": "navigation", + "purpose": "Theme-aware, responsive pagination component." + }, + { + "name": "Stepper", + "category": "navigation", + "purpose": "Theme-aware, responsive stepper component." + }, + { + "name": "Input", + "category": "forms", + "purpose": "Theme-aware, responsive input component." + }, + { + "name": "InputGroup", + "category": "forms", + "purpose": "Theme-aware, responsive input group component." + }, + { + "name": "Textarea", + "category": "forms", + "purpose": "Theme-aware, responsive textarea component." + }, + { + "name": "FileInput", + "category": "forms", + "purpose": "Theme-aware, responsive file input component." + }, + { + "name": "Checkbox", + "category": "forms", + "purpose": "Theme-aware, responsive checkbox component." + }, + { + "name": "Radio", + "category": "forms", + "purpose": "Theme-aware, responsive radio component." + }, + { + "name": "Switch", + "category": "forms", + "purpose": "Theme-aware, responsive switch component." + }, + { + "name": "Select", + "category": "forms", + "purpose": "Theme-aware, responsive select component." + }, + { + "name": "RangeSlider", + "category": "forms", + "purpose": "Theme-aware, responsive range slider component." + }, + { + "name": "ColorPicker", + "category": "forms", + "purpose": "Theme-aware, responsive color picker component." + }, + { + "name": "TimePicker", + "category": "forms", + "purpose": "Theme-aware, responsive time picker component." + }, + { + "name": "AdvancedSelect", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive advanced select component.", + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"] + }, + { + "name": "ComboBox", + "category": "advanced-forms", + "purpose": "Editable autocomplete combobox with local and remote suggestions.", + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"] + }, + { + "name": "SearchBox", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive search box component." + }, + { + "name": "InputNumber", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive input number component." + }, + { + "name": "StrongPassword", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive strong password component." + }, + { + "name": "TogglePassword", + "category": "advanced-forms", + "purpose": "Accessible password field with optional show and hide controls.", + "events": ["input", "change", "toggle"] + }, + { + "name": "ToggleCount", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive toggle count component." + }, + { + "name": "CopyMarkup", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive copy markup component." + }, + { + "name": "PinInput", + "category": "advanced-forms", + "purpose": "Secure multi-cell PIN and verification-code input with regex and paste support.", + "events": ["input", "change", "complete", "paste", "clear", "error"] + }, + { + "name": "Dropdown", + "category": "overlays", + "purpose": "Theme-aware, responsive dropdown component." + }, + { + "name": "ContextMenu", + "category": "overlays", + "purpose": "Theme-aware, responsive context menu component." + }, + { + "name": "Modal", + "category": "overlays", + "purpose": "Theme-aware, responsive modal component." + }, + { + "name": "Drawer", + "category": "overlays", + "purpose": "Theme-aware, responsive drawer component." + }, + { + "name": "Popover", + "category": "overlays", + "purpose": "Theme-aware, responsive popover component." + }, + { + "name": "Tooltip", + "category": "overlays", + "purpose": "Theme-aware, responsive tooltip component." + }, + { + "name": "Table", + "category": "tables", + "purpose": "Theme-aware, responsive table component." + }, + { + "name": "AdvancedRangeSlider", + "category": "integrations", + "purpose": "Theme-aware, responsive advanced range slider component." + }, + { + "name": "AdvancedDatePicker", + "category": "integrations", + "purpose": "Theme-aware, responsive advanced date picker component." + }, + { + "name": "Chart", + "category": "integrations", + "purpose": "Theme-aware, responsive chart component." + }, + { + "name": "Clipboard", + "category": "integrations", + "purpose": "Theme-aware, responsive clipboard component." + }, + { + "name": "Confetti", + "category": "integrations", + "purpose": "Theme-aware, responsive confetti component." + }, + { + "name": "DataMap", + "category": "integrations", + "purpose": "Theme-aware, responsive data map component." + }, + { + "name": "DataTable", + "category": "integrations", + "purpose": "Theme-aware, responsive data table component." + }, + { + "name": "DragAndDrop", + "category": "integrations", + "purpose": "Theme-aware, responsive drag and drop component." + }, + { + "name": "FileUpload", + "category": "integrations", + "purpose": "Theme-aware, responsive file upload component." + }, + { + "name": "Map", + "category": "integrations", + "purpose": "Theme-aware, responsive map component." + }, + { + "name": "ToastNotifications", + "category": "integrations", + "purpose": "Theme-aware, responsive toast notifications component." + }, + { + "name": "WysiwygEditor", + "category": "integrations", + "purpose": "Theme-aware, responsive wysiwyg editor component." + }, + { + "name": "PreferenceSwitcher", + "category": "navigation", + "purpose": "Accessible theme, accent color, and language preference controls." + }, + { + "name": "PortalDashboard", + "category": "blocks", + "purpose": "Responsive portal dashboard with metrics, actions, tasks, and updates." + }, + { + "name": "AuthSplitLayout", + "category": "layout", + "purpose": "Responsive 50/50 authentication layout with content and form regions." + }, + { + "name": "AuthForm", + "category": "forms", + "purpose": "Reusable authentication form for sign-in, registration, recovery, reset, and MFA." + } + ] +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/component-reference.json b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/component-reference.json new file mode 100644 index 00000000..facd2f0f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/component-reference.json @@ -0,0 +1,9761 @@ +{ + "generatedFrom": "packages/ui/components/*.wrn", + "count": 108, + "components": [ + { + "name": "Accordion", + "mount": "Accordion", + "category": "base", + "purpose": "Theme-aware, responsive accordion component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"accordion\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "defaultOpen", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "alwaysOpen", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "indicator", + "type": "string", + "required": false, + "default": "\"plus\"" + }, + { + "name": "indicatorPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "showIndicator", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "bordered", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "separated", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "flush", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "contentItalic", + "type": "boolean", + "required": false, + "default": "false" + } + ], + "slots": [], + "events": ["change", "open", "close"], + "source": "components/Accordion.wrn" + }, + { + "name": "AdvancedDatePicker", + "mount": "AdvancedDatePicker", + "category": "integrations", + "purpose": "Theme-aware, responsive advanced date picker component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Advanced Date Picker\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change", "open", "close", "clear"], + "source": "components/AdvancedDatePicker.wrn" + }, + { + "name": "AdvancedRangeSlider", + "mount": "AdvancedRangeSlider", + "category": "integrations", + "purpose": "Theme-aware, responsive advanced range slider component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Advanced Range Slider\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change", "start", "end"], + "source": "components/AdvancedRangeSlider.wrn" + }, + { + "name": "AdvancedSelect", + "mount": "AdvancedSelect", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive advanced select component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Advanced Select\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "values", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "groups", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Select an option\"" + }, + { + "name": "placeholderIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "searchPlaceholder", + "type": "string", + "required": false, + "default": "\"Search options…\"" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "searchable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "defaultOpen", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "clearable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "allowEmpty", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "tags", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "loading", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "loadingLabel", + "type": "string", + "required": false, + "default": "\"Loading options…\"" + }, + { + "name": "emptyLabel", + "type": "string", + "required": false, + "default": "\"No options found\"" + }, + { + "name": "selectedOptionsLabel", + "type": "string", + "required": false, + "default": "\"Selected options\"" + }, + { + "name": "clearLabel", + "type": "string", + "required": false, + "default": "\"Clear selection\"" + }, + { + "name": "createLabel", + "type": "string", + "required": false, + "default": "\"Create\"" + }, + { + "name": "loadMoreLabel", + "type": "string", + "required": false, + "default": "\"Load more\"" + }, + { + "name": "searchMode", + "type": "string", + "required": false, + "default": "\"contains\"" + }, + { + "name": "searchFields", + "type": "string", + "required": false, + "default": "\"label,description\"" + }, + { + "name": "minSearchLength", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "searchResultLimit", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "maxSelections", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "showCounter", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "counterTemplate", + "type": "string", + "required": false, + "default": "\"{selected} selected\"" + }, + { + "name": "optionTemplate", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "selectedTemplate", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "closeOnSelect", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "scrollToSelected", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fixed", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "remote", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "remoteUrl", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "remoteQueryParam", + "type": "string", + "required": false, + "default": "\"q\"" + }, + { + "name": "remoteDebounce", + "type": "number", + "required": false, + "default": "250" + }, + { + "name": "remoteAutoLoad", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "infinite", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "hasMore", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "page", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"], + "source": "components/AdvancedSelect.wrn" + }, + { + "name": "Alert", + "mount": "Alert", + "category": "base", + "purpose": "Theme-aware, responsive alert component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"info\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"soft\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "radius", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "shadow", + "type": "string", + "required": false, + "default": "\"sm\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Alert\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "actions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "showIcon", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "dismissible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dismissLabel", + "type": "string", + "required": false, + "default": "\"Dismiss alert\"" + }, + { + "name": "role", + "type": "string", + "required": false, + "default": "\"alert\"" + }, + { + "name": "live", + "type": "string", + "required": false, + "default": "\"polite\"" + }, + { + "name": "linkLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "linkHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "false" + } + ], + "slots": [], + "events": ["dismiss", "action"], + "source": "components/alert.wrn" + }, + { + "name": "AnnouncementBar", + "mount": "AnnouncementBar", + "category": "core", + "purpose": "Reusable announcement bar component.", + "props": [ + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badgeIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "message", + "type": "string", + "required": false, + "default": "\"Announcement\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--megaphone]\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "dismissible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dismissLabel", + "type": "string", + "required": false, + "default": "\"Dismiss announcement\"" + }, + { + "name": "sticky", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"soft\"" + }, + { + "name": "role", + "type": "string", + "required": false, + "default": "\"status\"" + }, + { + "name": "live", + "type": "string", + "required": false, + "default": "\"polite\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/AnnouncementBar.wrn" + }, + { + "name": "AuthForm", + "mount": "AuthForm", + "category": "forms", + "purpose": "Reusable authentication form for sign-in, registration, recovery, reset, and MFA.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "mode", + "type": "string", + "required": false, + "default": "\"sign-in\"" + }, + { + "name": "action", + "type": "string", + "required": false, + "default": "\"/api/auth/login\"" + }, + { + "name": "method", + "type": "string", + "required": false, + "default": "\"post\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Sign in\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "returnTo", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "schema", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "showRemember", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showName", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "submitLabel", + "type": "string", + "required": false, + "default": "\"Continue\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["submit", "change", "input", "focus", "blur"], + "source": "components/AuthForm.wrn" + }, + { + "name": "AuthSplitLayout", + "mount": "AuthSplitLayout", + "category": "layout", + "purpose": "Responsive 50/50 authentication layout with content and form regions.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"Secure identity\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Welcome back\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "brand", + "type": "string", + "required": false, + "default": "\"Police Management System\"" + }, + { + "name": "features", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["aside-extra", "form"], + "events": [], + "source": "components/AuthSplitLayout.wrn" + }, + { + "name": "Avatar", + "mount": "Avatar", + "category": "base", + "purpose": "Theme-aware, responsive avatar component.", + "props": [ + { + "name": "src", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "alt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "initials", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "shape", + "type": "string", + "required": false, + "default": "\"circle\"" + }, + { + "name": "status", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "statusLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "statusPosition", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badgeIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badgeLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "tooltip", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "loading", + "type": "string", + "required": false, + "default": "\"lazy\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["load", "error", "click"], + "source": "components/avatar.wrn" + }, + { + "name": "AvatarGroup", + "mount": "AvatarGroup", + "category": "base", + "purpose": "Theme-aware, responsive avatar group component.", + "props": [ + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "shape", + "type": "string", + "required": false, + "default": "\"circle\"" + }, + { + "name": "layout", + "type": "string", + "required": false, + "default": "\"stack\"" + }, + { + "name": "maxVisible", + "type": "number", + "required": false, + "default": "4" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "borderColor", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "showTooltips", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "overflowLabel", + "type": "string", + "required": false, + "default": "\"Show remaining members\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["overflow"], + "source": "components/AvatarGroup.wrn" + }, + { + "name": "BackToTop", + "mount": "BackToTop", + "category": "core", + "purpose": "Reusable back to top component.", + "props": [ + { + "name": "threshold", + "type": "number", + "required": false, + "default": "500" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Back to top\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Scroll back to top\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--arrow-up]\"" + }, + { + "name": "position", + "type": "string", + "required": false, + "default": "\"right\"" + }, + { + "name": "offset", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "behavior", + "type": "string", + "required": false, + "default": "\"smooth\"" + }, + { + "name": "showProgress", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/BackToTop.wrn" + }, + { + "name": "Badge", + "mount": "Badge", + "category": "base", + "purpose": "Theme-aware, responsive badge component.", + "props": [ + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Badge\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "shape", + "type": "string", + "required": false, + "default": "\"pill\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "dot", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dotOnly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dotLabel", + "type": "string", + "required": false, + "default": "\"Status\"" + }, + { + "name": "animated", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "avatarSrc", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "avatarAlt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "dismissible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dismissLabel", + "type": "string", + "required": false, + "default": "\"Remove badge\"" + }, + { + "name": "truncate", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"12rem\"" + }, + { + "name": "anchorLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "anchorIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"inline\"" + }, + { + "name": "anchorLabelText", + "type": "string", + "required": false, + "default": "\"Badge anchor\"" + } + ], + "slots": [], + "events": ["dismiss"], + "source": "components/Badge.wrn" + }, + { + "name": "Blockquote", + "mount": "Blockquote", + "category": "base", + "purpose": "Theme-aware, responsive blockquote component.", + "props": [ + { + "name": "quote", + "type": "string", + "required": false, + "default": "\"I just wanted to say that I'm very happy with my purchase so far. The documentation is outstanding - clear and detailed.\"" + }, + { + "name": "citation", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "citationTitle", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "citationUrl", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "avatarSrc", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "avatarAlt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "quoteMark", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "italic", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Blockquote.wrn" + }, + { + "name": "Breadcrumb", + "mount": "Breadcrumb", + "category": "navigation", + "purpose": "Theme-aware, responsive breadcrumb component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Breadcrumb\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["navigate", "click"], + "source": "components/Breadcrumb.wrn" + }, + { + "name": "Button", + "mount": "Button", + "category": "base", + "purpose": "Theme-aware, responsive button component.", + "props": [ + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Button\"" + }, + { + "name": "loadingLabel", + "type": "string", + "required": false, + "default": "\"Loading…\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "as", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "target", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "rel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"button\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "loading", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "pill", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "ariaPressed", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "ariaExpanded", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "ariaControls", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "autofocus", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "controlClass", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["click", "focus", "blur"], + "source": "components/button.wrn" + }, + { + "name": "ButtonGroup", + "mount": "ButtonGroup", + "category": "base", + "purpose": "Theme-aware, responsive button group component.", + "props": [ + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "responsive", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "attached", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "selectable", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "toolbar", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Button group\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["click", "select", "change"], + "source": "components/ButtonGroup.wrn" + }, + { + "name": "Card", + "mount": "Card", + "category": "base", + "purpose": "Theme-aware, responsive card component.", + "props": [ + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Card title\"" + }, + { + "name": "subtitle", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "header", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "footer", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "imageSrc", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "imageAlt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "imagePosition", + "type": "string", + "required": false, + "default": "\"top\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "headerActions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "navigation", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "activeNav", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "mobileNavigation", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "alertTitle", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "alertDescription", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "empty", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "emptyTitle", + "type": "string", + "required": false, + "default": "\"No data to show\"" + }, + { + "name": "emptyIcon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--inbox]\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "layout", + "type": "string", + "required": false, + "default": "\"vertical\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "hover", + "type": "string", + "required": false, + "default": "\"none\"" + }, + { + "name": "scrollable", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "maxHeight", + "type": "string", + "required": false, + "default": "\"18rem\"" + }, + { + "name": "dismissible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["click", "action", "navigate", "dismiss", "load", "error"], + "source": "components/Card.wrn" + }, + { + "name": "Carousel", + "mount": "Carousel", + "category": "base", + "purpose": "Theme-aware, responsive carousel component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "activeIndex", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "slidesPerView", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"0.75rem\"" + }, + { + "name": "showPagination", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isAutoPlay", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "autoplayInterval", + "type": "number", + "required": false, + "default": "4000" + }, + { + "name": "isInfiniteLoop", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isRTL", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isCentered", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isDraggable", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isAutoHeight", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isSnap", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showCounter", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "thumbnails", + "type": "string", + "required": false, + "default": "\"none\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Content carousel\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [ + "initialize", + "change", + "previous", + "next", + "play", + "pause", + "reachStart", + "reachEnd", + "dragStart", + "dragEnd" + ], + "source": "components/carousel.wrn" + }, + { + "name": "Chart", + "mount": "Chart", + "category": "integrations", + "purpose": "Theme-aware, responsive chart component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Chart\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "dataPointClick", "legendToggle"], + "source": "components/Chart.wrn" + }, + { + "name": "ChatBubble", + "mount": "ChatBubble", + "category": "base", + "purpose": "Theme-aware, responsive chat bubble component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "oneSided", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showAvatars", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showMetadata", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Conversation\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["action", "messageClick", "avatarClick", "linkClick"], + "source": "components/ChatBubble.wrn" + }, + { + "name": "Checkbox", + "mount": "Checkbox", + "category": "forms", + "purpose": "Theme-aware, responsive checkbox component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Checkbox\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"on\"" + }, + { + "name": "values", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "checked", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "indeterminate", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"vertical\"" + }, + { + "name": "card", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "rightAligned", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "list", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change", "focus", "blur", "invalid"], + "source": "components/Checkbox.wrn" + }, + { + "name": "Clipboard", + "mount": "Clipboard", + "category": "integrations", + "purpose": "Theme-aware, responsive clipboard component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Clipboard\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["copy", "success", "error"], + "source": "components/Clipboard.wrn" + }, + { + "name": "Collapse", + "mount": "Collapse", + "category": "base", + "purpose": "Theme-aware, responsive collapse component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "mode", + "type": "string", + "required": false, + "default": "\"panel\"" + }, + { + "name": "initialOpenIndexes", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Collapsible content\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["toggle", "open", "close"], + "source": "components/Collapse.wrn" + }, + { + "name": "ColorPicker", + "mount": "ColorPicker", + "category": "forms", + "purpose": "Theme-aware, responsive color picker component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Color\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"#2563eb\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur"], + "source": "components/ColorPicker.wrn" + }, + { + "name": "Columns", + "mount": "Columns", + "category": "layout", + "purpose": "Theme-aware, responsive columns component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Columns.wrn" + }, + { + "name": "ComboBox", + "mount": "ComboBox", + "category": "advanced-forms", + "purpose": "Editable autocomplete combobox with local and remote suggestions.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"ComboBox\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "groups", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Search or select an option\"" + }, + { + "name": "searchPlaceholder", + "type": "string", + "required": false, + "default": "\"Start typing…\"" + }, + { + "name": "clearable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "allowCustomValue", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "loading", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "loadingLabel", + "type": "string", + "required": false, + "default": "\"Loading suggestions…\"" + }, + { + "name": "emptyLabel", + "type": "string", + "required": false, + "default": "\"No matching options\"" + }, + { + "name": "clearLabel", + "type": "string", + "required": false, + "default": "\"Clear value\"" + }, + { + "name": "toggleLabel", + "type": "string", + "required": false, + "default": "\"Toggle suggestions\"" + }, + { + "name": "searchMode", + "type": "string", + "required": false, + "default": "\"contains\"" + }, + { + "name": "searchFields", + "type": "string", + "required": false, + "default": "\"label,description\"" + }, + { + "name": "minSearchLength", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "searchResultLimit", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "optionTemplate", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "defaultOpen", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "closeOnSelect", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fixed", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"off\"" + }, + { + "name": "remote", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "remoteUrl", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "remoteQueryParam", + "type": "string", + "required": false, + "default": "\"q\"" + }, + { + "name": "remoteDebounce", + "type": "number", + "required": false, + "default": "250" + }, + { + "name": "remoteAutoLoad", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "infinite", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "hasMore", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "page", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "loadMoreLabel", + "type": "string", + "required": false, + "default": "\"Load more\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"], + "source": "components/Combobox.wrn" + }, + { + "name": "Confetti", + "mount": "Confetti", + "category": "integrations", + "purpose": "Theme-aware, responsive confetti component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Confetti\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["start", "complete"], + "source": "components/Confetti.wrn" + }, + { + "name": "Container", + "mount": "Container", + "category": "layout", + "purpose": "Theme-aware, responsive container component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Container.wrn" + }, + { + "name": "ContextMenu", + "mount": "ContextMenu", + "category": "overlays", + "purpose": "Theme-aware, responsive context menu component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Context Menu\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close", "select"], + "source": "components/ContextMenu.wrn" + }, + { + "name": "CopyMarkup", + "mount": "CopyMarkup", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive copy markup component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Copy Markup\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"text\"" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["copy", "success", "error"], + "source": "components/CopyMarkup.wrn" + }, + { + "name": "CTASection", + "mount": "CTASection", + "category": "core", + "purpose": "Reusable ctasection component.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Ready to get started?\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"center\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"Get started\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"#\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "backgroundImage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default", "actions", "visual", "footer"], + "events": [], + "source": "components/CTASection.wrn" + }, + { + "name": "CustomScrollbar", + "mount": "CustomScrollbar", + "category": "layout", + "purpose": "Theme-aware, responsive custom scrollbar component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["scroll"], + "source": "components/CustomScrollbar.wrn" + }, + { + "name": "DataMap", + "mount": "DataMap", + "category": "integrations", + "purpose": "Theme-aware, responsive data map component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Data Map\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "change"], + "source": "components/DataMap.wrn" + }, + { + "name": "DataTable", + "mount": "DataTable", + "category": "integrations", + "purpose": "Theme-aware, responsive data table component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "caption", + "type": "string", + "required": false, + "default": "\"Data Table\"" + }, + { + "name": "columns", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "rows", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "striped", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["sort", "select", "change", "rowClick", "pageChange"], + "source": "components/DataTable.wrn" + }, + { + "name": "DatePicker", + "mount": "DatePicker", + "category": "base", + "purpose": "Theme-aware, responsive date picker component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Date Picker\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"date\"" + }, + { + "name": "locale", + "type": "string", + "required": false, + "default": "\"en-US\"" + }, + { + "name": "firstDayOfWeek", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "months", + "type": "string", + "required": false, + "default": "[{ label: \"Jan\", value: \"01\" }, { label: \"Feb\", value: \"02\" }, { label: \"Mar\", value: \"03\" }, { label: \"Apr\", value: \"04\" }, { label: \"May\", value: \"05\" }, { label: \"Jun\", value: \"06\" }, { label: \"Jul\", value: \"07\" }, { label: \"Aug\", value: \"08\" }, { label: \"Sep\", value: \"09\" }, { label: \"Oct\", value: \"10\" }, { label: \"Nov\", value: \"11\" }, { label: \"Dec\", value: \"12\" }]" + }, + { + "name": "days", + "type": "string", + "required": false, + "default": "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]" + }, + { + "name": "years", + "type": "string", + "required": false, + "default": "[2024, 2025, 2026, 2027, 2028, 2029, 2030]" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "open", "close", "focus", "blur", "invalid"], + "source": "components/DatePicker.wrn" + }, + { + "name": "DeviceFrame", + "mount": "DeviceFrame", + "category": "base", + "purpose": "Theme-aware, responsive device frame component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Device Frame\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "device", + "type": "string", + "required": false, + "default": "\"phone\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"portrait\"" + }, + { + "name": "src", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "srcdoc", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "frameTitle", + "type": "string", + "required": false, + "default": "\"Device preview\"" + }, + { + "name": "showToolbar", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "allow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["change", "rotate"], + "source": "components/DeviceFrame.wrn" + }, + { + "name": "Divider", + "mount": "Divider", + "category": "layout", + "purpose": "Theme-aware, responsive divider component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/Divider.wrn" + }, + { + "name": "DragAndDrop", + "mount": "DragAndDrop", + "category": "integrations", + "purpose": "Theme-aware, responsive drag and drop component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Drag And Drop\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["dragStart", "dragEnd", "dragEnter", "dragLeave", "drop", "change"], + "source": "components/DragAndDrop.wrn" + }, + { + "name": "Drawer", + "mount": "Drawer", + "category": "overlays", + "purpose": "Theme-aware, responsive drawer component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Drawer\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close"], + "source": "components/Drawer.wrn" + }, + { + "name": "Dropdown", + "mount": "Dropdown", + "category": "overlays", + "purpose": "Theme-aware, responsive dropdown component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Open menu\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"end\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["trigger", "header", "footer"], + "events": ["toggle", "open", "close", "select"], + "source": "components/Dropdown.wrn" + }, + { + "name": "FeatureCard", + "mount": "FeatureCard", + "category": "core", + "purpose": "Reusable feature card component.", + "props": [ + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Feature\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"Learn more\"" + }, + { + "name": "actionIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badgeColor", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "hover", + "type": "string", + "required": false, + "default": "\"lift\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["icon", "default", "footer"], + "events": [], + "source": "components/FeatureCard.wrn" + }, + { + "name": "FeatureGrid", + "mount": "FeatureGrid", + "category": "core", + "purpose": "Reusable feature grid component.", + "props": [ + { + "name": "columns", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "tabletColumns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "mobileColumns", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "minItemWidth", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "equalHeight", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"stretch\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"full\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/FeatureGrid.wrn" + }, + { + "name": "FeatureIconCard", + "mount": "FeatureIconCard", + "category": "core", + "purpose": "Reusable feature icon card component.", + "props": [ + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--sparkles]\"" + }, + { + "name": "iconSize", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "iconVariant", + "type": "string", + "required": false, + "default": "\"soft\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Feature\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"Explore\"" + }, + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "hover", + "type": "string", + "required": false, + "default": "\"lift\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default", "footer"], + "events": [], + "source": "components/FeatureIconCard.wrn" + }, + { + "name": "FileInput", + "mount": "FileInput", + "category": "forms", + "purpose": "Theme-aware, responsive file input component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"File\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Choose a file\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--upload]\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "accept", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "select", "clear", "invalid"], + "source": "components/FileInput.wrn" + }, + { + "name": "FileUpload", + "mount": "FileUpload", + "category": "integrations", + "purpose": "Theme-aware, responsive file upload component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"File Upload\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "upload", "progress", "success", "error", "cancel", "remove"], + "source": "components/FileUpload.wrn" + }, + { + "name": "FileUploadProgress", + "mount": "FileUploadProgress", + "category": "base", + "purpose": "Theme-aware, responsive file upload progress component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Progress\"" + }, + { + "name": "value", + "type": "number", + "required": false, + "default": "50" + }, + { + "name": "max", + "type": "number", + "required": false, + "default": "100" + }, + { + "name": "showValue", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fileName", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "fileSize", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "uploadedSize", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "status", + "type": "string", + "required": false, + "default": "\"uploading\"" + }, + { + "name": "cancelLabel", + "type": "string", + "required": false, + "default": "\"Cancel upload\"" + }, + { + "name": "retryLabel", + "type": "string", + "required": false, + "default": "\"Retry upload\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["cancel", "retry", "complete"], + "source": "components/FileUploadProgress.wrn" + }, + { + "name": "Footer", + "mount": "Footer", + "category": "navigation", + "purpose": "Responsive application footer with structured links and pre/post content slots.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Footer navigation\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"compact\"" + }, + { + "name": "copyright", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["pre-footer", "copyright-left", "copyright-right", "post-footer"], + "events": ["select", "action"], + "source": "components/Footer.wrn" + }, + { + "name": "Grid", + "mount": "Grid", + "category": "layout", + "purpose": "Theme-aware, responsive grid component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Grid.wrn" + }, + { + "name": "Hero", + "mount": "Hero", + "category": "core", + "purpose": "Reusable hero component.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Build something remarkable\"" + }, + { + "name": "highlight", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "tertiaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "tertiaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badges", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "trustItems", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["eyebrow", "actions", "trust", "default", "visual", "footer"], + "events": [], + "source": "components/Hero.wrn" + }, + { + "name": "HeroActions", + "mount": "HeroActions", + "category": "core", + "purpose": "Reusable hero actions component.", + "props": [ + { + "name": "actions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "stackOnMobile", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fullWidthMobile", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/HeroActions.wrn" + }, + { + "name": "Image", + "mount": "Image", + "category": "layout", + "purpose": "Theme-aware, responsive image component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "src", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "alt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "width", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "height", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "loading", + "type": "string", + "required": false, + "default": "\"lazy\"" + }, + { + "name": "rounded", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Image.wrn" + }, + { + "name": "Input", + "mount": "Input", + "category": "forms", + "purpose": "Theme-aware, responsive input component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Input\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"text\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inputmode", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "minlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "maxlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "pattern", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "invalid", "keydown", "keyup"], + "source": "components/Input.wrn" + }, + { + "name": "InputGroup", + "mount": "InputGroup", + "category": "forms", + "purpose": "Theme-aware, responsive input group component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Input group\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"text\"" + }, + { + "name": "startText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "endText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "submit", "action"], + "source": "components/InputGroup.wrn" + }, + { + "name": "InputNumber", + "mount": "InputNumber", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive input number component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"quantity\"" + }, + { + "name": "value", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "precision", + "type": "string", + "required": false, + "default": "\"auto\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "prefix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "suffix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"off\"" + }, + { + "name": "inputMode", + "type": "string", + "required": false, + "default": "\"decimal\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "inputDisabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "buttonsDisabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "allowInput", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "keyboard", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "wheel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "clamp", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showButtons", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showValidationMessage", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "decrementLabel", + "type": "string", + "required": false, + "default": "\"Decrease value\"" + }, + { + "name": "incrementLabel", + "type": "string", + "required": false, + "default": "\"Increase value\"" + }, + { + "name": "controlsLabel", + "type": "string", + "required": false, + "default": "\"Quantity controls\"" + }, + { + "name": "requiredMessage", + "type": "string", + "required": false, + "default": "\"A value is required.\"" + }, + { + "name": "minMessage", + "type": "string", + "required": false, + "default": "\"Value is below the minimum.\"" + }, + { + "name": "maxMessage", + "type": "string", + "required": false, + "default": "\"Value is above the maximum.\"" + } + ], + "slots": [], + "events": ["input", "change", "increment", "decrement"], + "source": "components/InputNumber.wrn" + }, + { + "name": "Kbd", + "mount": "Kbd", + "category": "layout", + "purpose": "Theme-aware, responsive kbd component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"⌘ K\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Kbd.wrn" + }, + { + "name": "LayoutSplitter", + "mount": "LayoutSplitter", + "category": "layout", + "purpose": "Theme-aware, responsive layout splitter component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["resizeStart", "resize", "resizeEnd"], + "source": "components/LayoutSplitter.wrn" + }, + { + "name": "LegendIndicator", + "mount": "LegendIndicator", + "category": "base", + "purpose": "Theme-aware, responsive legend indicator component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Legend Indicator\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["toggle", "select"], + "source": "components/LegendIndicator.wrn" + }, + { + "name": "Link", + "mount": "Link", + "category": "layout", + "purpose": "Theme-aware, responsive link component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Link\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"#\"" + }, + { + "name": "target", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "rel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "external", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Link.wrn" + }, + { + "name": "List", + "mount": "List", + "category": "base", + "purpose": "Theme-aware, responsive list component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"List\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/List.wrn" + }, + { + "name": "ListGroup", + "mount": "ListGroup", + "category": "base", + "purpose": "Theme-aware, responsive list group component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"List Group\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "change"], + "source": "components/ListGroup.wrn" + }, + { + "name": "Map", + "mount": "Map", + "category": "integrations", + "purpose": "Theme-aware, responsive map component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Map\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Map.wrn" + }, + { + "name": "MarketingSectionHeader", + "mount": "MarketingSectionHeader", + "category": "core", + "purpose": "Reusable marketing section header component.", + "props": [ + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"split\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionExternal", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["icon", "actions", "default"], + "events": [], + "source": "components/MarketingSectionHeader.wrn" + }, + { + "name": "Marquee", + "mount": "Marquee", + "category": "base", + "purpose": "Theme-aware, responsive marquee component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Marquee\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Marquee.wrn" + }, + { + "name": "MegaMenu", + "mount": "MegaMenu", + "category": "navigation", + "purpose": "Theme-aware, responsive mega menu component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Mega Menu\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close", "select"], + "source": "components/MegaMenu.wrn" + }, + { + "name": "MetricCard", + "mount": "MetricCard", + "category": "core", + "purpose": "Reusable metric card component.", + "props": [ + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Metric\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"0\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "prefix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "suffix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "trend", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "trendLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "trendDirection", + "type": "string", + "required": false, + "default": "\"neutral\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/MetricCard.wrn" + }, + { + "name": "MetricGrid", + "mount": "MetricGrid", + "category": "core", + "purpose": "Reusable metric grid component.", + "props": [ + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "4" + }, + { + "name": "tabletColumns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "mobileColumns", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "equalHeight", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "dividers", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/MetricGrid.wrn" + }, + { + "name": "Modal", + "mount": "Modal", + "category": "overlays", + "purpose": "Theme-aware, responsive modal component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Modal\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close", "cancel", "confirm"], + "source": "components/Modal.wrn" + }, + { + "name": "Nav", + "mount": "Nav", + "category": "navigation", + "purpose": "Theme-aware, responsive nav component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Nav\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "change"], + "source": "components/Nav.wrn" + }, + { + "name": "Navbar", + "mount": "Navbar", + "category": "navigation", + "purpose": "Theme-aware, responsive navbar component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Primary navigation\"" + }, + { + "name": "topbarLabel", + "type": "string", + "required": false, + "default": "\"Utility navigation\"" + }, + { + "name": "brand", + "type": "string", + "required": false, + "default": "{}" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "actions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "sticky", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "openOnHover", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"full\"" + }, + { + "name": "mobileLabel", + "type": "string", + "required": false, + "default": "\"Toggle navigation\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["topbar", "actions"], + "events": ["toggle", "open", "close", "select", "action"], + "source": "components/Navbar.wrn" + }, + { + "name": "PageHeader", + "mount": "PageHeader", + "category": "core", + "purpose": "Reusable page header component.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showBreadcrumbs", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "breadcrumbs", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["meta", "actions", "default"], + "events": [], + "source": "components/PageHeader.wrn" + }, + { + "name": "Pagination", + "mount": "Pagination", + "category": "navigation", + "purpose": "Theme-aware, responsive pagination component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Pagination\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["change", "previous", "next"], + "source": "components/Pagination.wrn" + }, + { + "name": "PinInput", + "mount": "PinInput", + "category": "advanced-forms", + "purpose": "Secure multi-cell PIN and verification-code input with regex and paste support.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Verification code\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"pin\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "length", + "type": "number", + "required": false, + "default": "4" + }, + { + "name": "pattern", + "type": "string", + "required": false, + "default": "\"[0-9]\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"text\"" + }, + { + "name": "inputMode", + "type": "string", + "required": false, + "default": "\"numeric\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"○\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"one-time-code\"" + }, + { + "name": "masked", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "autoFocus", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "autoSubmit", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "allowPaste", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "clearable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "clearLabel", + "type": "string", + "required": false, + "default": "\"Clear code\"" + }, + { + "name": "separator", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "groupSize", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "complete", "paste", "clear", "error"], + "source": "components/PinInput.wrn" + }, + { + "name": "Popover", + "mount": "Popover", + "category": "overlays", + "purpose": "Theme-aware, responsive popover component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Popover\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close"], + "source": "components/Popover.wrn" + }, + { + "name": "PortalDashboard", + "mount": "PortalDashboard", + "category": "blocks", + "purpose": "Responsive portal dashboard with metrics, actions, tasks, and updates.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"Overview\"" + }, + { + "name": "eyebrowKey", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Dashboard\"" + }, + { + "name": "titleKey", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "descriptionKey", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "userName", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "metrics", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "actions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "updates", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "tasks", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["hero-action"], + "events": ["action", "navigate"], + "source": "components/PortalDashboard.wrn" + }, + { + "name": "PreferenceSwitcher", + "mount": "PreferenceSwitcher", + "category": "navigation", + "purpose": "Accessible theme, accent color, and language preference controls.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "themeLabel", + "type": "string", + "required": false, + "default": "\"Theme\"" + }, + { + "name": "colorLabel", + "type": "string", + "required": false, + "default": "\"Accent color\"" + }, + { + "name": "languageLabel", + "type": "string", + "required": false, + "default": "\"Language\"" + }, + { + "name": "languages", + "type": "string", + "required": false, + "default": "[" + }, + { + "name": "colors", + "type": "string", + "required": false, + "default": "[" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["theme", "color", "language"], + "source": "components/PreferenceSwitcher.wrn" + }, + { + "name": "Progress", + "mount": "Progress", + "category": "base", + "purpose": "Theme-aware, responsive progress component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Progress\"" + }, + { + "name": "value", + "type": "number", + "required": false, + "default": "50" + }, + { + "name": "max", + "type": "number", + "required": false, + "default": "100" + }, + { + "name": "showValue", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/progress.wrn" + }, + { + "name": "PublicPageShell", + "mount": "PublicPageShell", + "category": "core", + "purpose": "Reusable public page shell component.", + "props": [ + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"full\"" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "headerOffset", + "type": "string", + "required": false, + "default": "\"none\"" + }, + { + "name": "background", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "overflow", + "type": "string", + "required": false, + "default": "\"clip\"" + }, + { + "name": "minHeight", + "type": "string", + "required": false, + "default": "\"screen\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["before", "default", "after"], + "events": [], + "source": "components/PublicPageShell.wrn" + }, + { + "name": "Radio", + "mount": "Radio", + "category": "forms", + "purpose": "Theme-aware, responsive radio component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Radio\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"on\"" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "checked", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"vertical\"" + }, + { + "name": "card", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "rightAligned", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "list", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "invalid"], + "source": "components/Radio.wrn" + }, + { + "name": "RangeSlider", + "mount": "RangeSlider", + "category": "forms", + "purpose": "Theme-aware, responsive range slider component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Range\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "value", + "type": "number", + "required": false, + "default": "50" + }, + { + "name": "min", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "max", + "type": "number", + "required": false, + "default": "100" + }, + { + "name": "step", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "showValue", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showBounds", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showSteps", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "marks", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur"], + "source": "components/RangeSlider.wrn" + }, + { + "name": "Rating", + "mount": "Rating", + "category": "base", + "purpose": "Theme-aware, responsive rating component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Rating\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change"], + "source": "components/Rating.wrn" + }, + { + "name": "Scrollspy", + "mount": "Scrollspy", + "category": "navigation", + "purpose": "Theme-aware, responsive scrollspy component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Scrollspy\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["change"], + "source": "components/Scrollspy.wrn" + }, + { + "name": "SearchBox", + "mount": "SearchBox", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive search box component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Search Box\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"search\"" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/SearchBox.wrn" + }, + { + "name": "Section", + "mount": "Section", + "category": "core", + "purpose": "Reusable section component.", + "props": [ + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "spacing", + "type": "string", + "required": false, + "default": "\"lg\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "borderTop", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "borderBottom", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Section.wrn" + }, + { + "name": "SectionHeader", + "mount": "SectionHeader", + "category": "core", + "purpose": "Reusable section header component.", + "props": [ + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "headingLevel", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"3xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["icon", "default", "actions"], + "events": [], + "source": "components/SectionHeader.wrn" + }, + { + "name": "Select", + "mount": "Select", + "category": "forms", + "purpose": "Theme-aware, responsive select component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Select\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "values", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Select an option\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "open", "close", "invalid"], + "source": "components/Select.wrn" + }, + { + "name": "Sidebar", + "mount": "Sidebar", + "category": "navigation", + "purpose": "Theme-aware, responsive sidebar component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Sidebar\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "mobileLabel", + "type": "string", + "required": false, + "default": "\"Open navigation\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["toggle", "open", "close", "select"], + "source": "components/Sidebar.wrn" + }, + { + "name": "Skeleton", + "mount": "Skeleton", + "category": "base", + "purpose": "Theme-aware, responsive skeleton component.", + "props": [ + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Loading\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "lines", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/skeleton.wrn" + }, + { + "name": "Spinner", + "mount": "Spinner", + "category": "base", + "purpose": "Theme-aware, responsive spinner component.", + "props": [ + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Loading\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "lines", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/spinner.wrn" + }, + { + "name": "SplitHero", + "mount": "SplitHero", + "category": "core", + "purpose": "Reusable split hero component.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"A better digital experience\"" + }, + { + "name": "highlight", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "visualPosition", + "type": "string", + "required": false, + "default": "\"right\"" + }, + { + "name": "reverse", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "ratio", + "type": "string", + "required": false, + "default": "\"balanced\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "trustItems", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["actions", "trust", "default", "visual"], + "events": [], + "source": "components/SplitHero.wrn" + }, + { + "name": "StatsBar", + "mount": "StatsBar", + "category": "core", + "purpose": "Reusable stats bar component.", + "props": [ + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "4" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "dividers", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "icons", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"raised\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/StatsBar.wrn" + }, + { + "name": "Stepper", + "mount": "Stepper", + "category": "navigation", + "purpose": "Theme-aware, responsive stepper component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Stepper\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["change", "previous", "next", "complete"], + "source": "components/Stepper.wrn" + }, + { + "name": "StrongPassword", + "mount": "StrongPassword", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive strong password component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Password\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"password\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Create a strong password\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"new-password\"" + }, + { + "name": "minLength", + "type": "number", + "required": false, + "default": "8" + }, + { + "name": "specialCharactersSet", + "type": "string", + "required": false, + "default": "\"!@#$%^&*()_+-=[]{}|;:,.<>?\"" + }, + { + "name": "requireLowercase", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "requireUppercase", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "requireNumber", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "requireSpecialCharacter", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showRequirements", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "presentation", + "type": "string", + "required": false, + "default": "\"inline\"" + }, + { + "name": "hintText", + "type": "string", + "required": false, + "default": "\"Use a unique password you do not use elsewhere.\"" + }, + { + "name": "emptyLabel", + "type": "string", + "required": false, + "default": "\"Enter a password\"" + }, + { + "name": "weakLabel", + "type": "string", + "required": false, + "default": "\"Weak\"" + }, + { + "name": "fairLabel", + "type": "string", + "required": false, + "default": "\"Fair\"" + }, + { + "name": "goodLabel", + "type": "string", + "required": false, + "default": "\"Good\"" + }, + { + "name": "strongLabel", + "type": "string", + "required": false, + "default": "\"Strong\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "strength"], + "source": "components/StrongPassword.wrn" + }, + { + "name": "StyledIcon", + "mount": "StyledIcon", + "category": "base", + "purpose": "Theme-aware, responsive styled icon component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Styled Icon\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/StyledIcon.wrn" + }, + { + "name": "Switch", + "mount": "Switch", + "category": "forms", + "purpose": "Theme-aware, responsive switch component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Switch\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"on\"" + }, + { + "name": "checked", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur"], + "source": "components/Switch.wrn" + }, + { + "name": "Table", + "mount": "Table", + "category": "tables", + "purpose": "Theme-aware, responsive table component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "caption", + "type": "string", + "required": false, + "default": "\"Table\"" + }, + { + "name": "columns", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "rows", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "striped", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["sort", "select", "rowClick"], + "source": "components/table.wrn" + }, + { + "name": "Tabs", + "mount": "Tabs", + "category": "navigation", + "purpose": "Theme-aware, responsive tabs component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Tabs\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Tabs.wrn" + }, + { + "name": "Textarea", + "mount": "Textarea", + "category": "forms", + "purpose": "Theme-aware, responsive textarea component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Textarea\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "rows", + "type": "number", + "required": false, + "default": "5" + }, + { + "name": "resize", + "type": "string", + "required": false, + "default": "\"vertical\"" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "minlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "maxlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "invalid"], + "source": "components/Textarea.wrn" + }, + { + "name": "TextLink", + "mount": "TextLink", + "category": "core", + "purpose": "Reusable text link component.", + "props": [ + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Learn more\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"#\"" + }, + { + "name": "target", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "rel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "external", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "showArrow", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "underline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["click", "focus", "blur"], + "source": "components/TextLink.wrn" + }, + { + "name": "Timeline", + "mount": "Timeline", + "category": "base", + "purpose": "Theme-aware, responsive timeline component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Timeline\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Timeline.wrn" + }, + { + "name": "TimePicker", + "mount": "TimePicker", + "category": "forms", + "purpose": "Theme-aware, responsive time picker component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Time\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--clock-3]\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"end\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "format", + "type": "string", + "required": false, + "default": "\"24\"" + }, + { + "name": "minuteStep", + "type": "number", + "required": false, + "default": "5" + }, + { + "name": "hours", + "type": "string", + "required": false, + "default": "[\"00\", \"01\", \"02\", \"03\", \"04\", \"05\", \"06\", \"07\", \"08\", \"09\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"20\", \"21\", \"22\", \"23\"]" + }, + { + "name": "minutes", + "type": "string", + "required": false, + "default": "[\"00\", \"05\", \"10\", \"15\", \"20\", \"25\", \"30\", \"35\", \"40\", \"45\", \"50\", \"55\"]" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "open", "close", "invalid"], + "source": "components/TimePicker.wrn" + }, + { + "name": "Toast", + "mount": "Toast", + "category": "base", + "purpose": "Theme-aware, responsive toast component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Toast\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["dismiss", "action"], + "source": "components/Toast.wrn" + }, + { + "name": "ToastNotifications", + "mount": "ToastNotifications", + "category": "integrations", + "purpose": "Theme-aware, responsive toast notifications component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Toast Notifications\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["add", "dismiss", "clear", "action"], + "source": "components/ToastNotifications.wrn" + }, + { + "name": "ToggleCount", + "mount": "ToggleCount", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive toggle count component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"segmented\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"billing-cycle\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"monthly\"" + }, + { + "name": "firstValue", + "type": "string", + "required": false, + "default": "\"monthly\"" + }, + { + "name": "firstLabel", + "type": "string", + "required": false, + "default": "\"Monthly\"" + }, + { + "name": "secondValue", + "type": "string", + "required": false, + "default": "\"annual\"" + }, + { + "name": "secondLabel", + "type": "string", + "required": false, + "default": "\"Annual\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Billing frequency\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "currency", + "type": "string", + "required": false, + "default": "\"$\"" + }, + { + "name": "suffix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "firstValueKey", + "type": "string", + "required": false, + "default": "\"monthly\"" + }, + { + "name": "secondValueKey", + "type": "string", + "required": false, + "default": "\"annual\"" + }, + { + "name": "emptyValue", + "type": "string", + "required": false, + "default": "\"—\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"end\"" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "animate", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "animationDuration", + "type": "number", + "required": false, + "default": "450" + }, + { + "name": "animationSteps", + "type": "number", + "required": false, + "default": "18" + } + ], + "slots": [], + "events": ["change", "toggle"], + "source": "components/ToggleCount.wrn" + }, + { + "name": "TogglePassword", + "mount": "TogglePassword", + "category": "advanced-forms", + "purpose": "Accessible password field with optional show and hide controls.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Password\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"password\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Enter your password\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"current-password\"" + }, + { + "name": "minlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "maxlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "pattern", + "type": "string", + "required": false, + "default": "\"(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}\"" + }, + { + "name": "fields", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "visible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "toggleable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "toggleMode", + "type": "string", + "required": false, + "default": "\"button\"" + }, + { + "name": "checkboxLabel", + "type": "string", + "required": false, + "default": "\"Show password\"" + }, + { + "name": "showLabel", + "type": "string", + "required": false, + "default": "\"Show password\"" + }, + { + "name": "hideLabel", + "type": "string", + "required": false, + "default": "\"Hide password\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "toggle"], + "source": "components/TogglePassword.wrn" + }, + { + "name": "Tooltip", + "mount": "Tooltip", + "category": "overlays", + "purpose": "Theme-aware, responsive tooltip component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Tooltip\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close"], + "source": "components/tooltip.wrn" + }, + { + "name": "TreeView", + "mount": "TreeView", + "category": "base", + "purpose": "Theme-aware, responsive tree view component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Tree View\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "toggle", "expand", "collapse"], + "source": "components/TreeView.wrn" + }, + { + "name": "Typography", + "mount": "Typography", + "category": "layout", + "purpose": "Theme-aware, responsive typography component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Typography.wrn" + }, + { + "name": "WysiwygEditor", + "mount": "WysiwygEditor", + "category": "integrations", + "purpose": "Theme-aware, responsive wysiwyg editor component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Wysiwyg Editor\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change", "focus", "blur"], + "source": "components/WysiwygEditor.wrn" + } + ] +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/progress.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/progress.wrn new file mode 100644 index 00000000..dea093ca --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/progress.wrn @@ -0,0 +1,17 @@ +component Progress { + props { + size = "default" + color = "primary" + label = "Progress" + value = 50 + max = 100 + showValue = true + class = "" + } + view { +
+
{label}{#if showValue}{value}%{/if}
+ +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/skeleton.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/skeleton.wrn new file mode 100644 index 00000000..3adaf9fd --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/skeleton.wrn @@ -0,0 +1,14 @@ +component Skeleton { + props { + color = "primary" + label = "Loading" + size = "md" + lines = 3 + class = "" + } + view { +
+ {#if "Skeleton" === "Skeleton"}{#each Array(lines).fill(0) as line}{/each}{:else}{/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/spinner.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/spinner.wrn new file mode 100644 index 00000000..bd607734 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/spinner.wrn @@ -0,0 +1,14 @@ +component Spinner { + props { + color = "primary" + label = "Loading" + size = "md" + lines = 3 + class = "" + } + view { +
+ {#if "Spinner" === "Skeleton"}{#each Array(lines).fill(0) as line}{/each}{:else}{/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/table.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/table.wrn new file mode 100644 index 00000000..1f5dc29f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/table.wrn @@ -0,0 +1,17 @@ +component Table { + props { + @event sort = function + @event select = function + @event rowClick = function + size = "default" + color = "primary" + caption = "Table" + columns = [] + rows = [] + striped = true + class = "" + } + view { +
{#each columns as column}{/each}{#each rows as row}{#each columns as column}{/each}{/each}
{caption}
{column.label}
{row[column.key]}
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/tooltip.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/tooltip.wrn new file mode 100644 index 00000000..240da14c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/tooltip.wrn @@ -0,0 +1,21 @@ +component Tooltip { + props { + @event open = function + @event close = function + size = "default" + color = "primary" + title = "Tooltip" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { +
+
{title}
+ {#if description}

{description}

{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ui.test.ts b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ui.test.ts new file mode 100644 index 00000000..a2e58345 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-49-55-005Z/ui.test.ts @@ -0,0 +1,2438 @@ +import { expect, test } from "bun:test"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import { compileWireFile } from "../../compiler/src/index.ts"; +import { mountHtml, renderComponent } from "../../test/src/index.ts"; +import { uiComponentNames, uiComponentsDir, uiComponentPath, uiCss } from "../src/index.ts"; + +test("bundled UI assets are discoverable and readable", () => { + expect(uiComponentNames()).toContain("Button"); + expect(uiComponentNames()).toContain("Accordion"); + expect(uiComponentNames()).toContain("DataTable"); + expect(uiComponentNames()).toContain("WysiwygEditor"); + expect(readFileSync(uiComponentPath("Button"), "utf8")).toContain("component Button"); + expect(uiCss()).toContain("--wire-"); +}); + +test("generated component reference documents every bundled component and its props", () => { + const reference = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-reference.json"), "utf8"), + ) as { count: number; components: Array<{ name: string; props: Array<{ name: string }> }> }; + const catalog = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-catalog.json"), "utf8"), + ) as { components: Array<{ name: string }> }; + expect(reference.count).toBe(uiComponentNames().length); + expect(reference.count).toBe(90); + expect(reference.components.map((component) => component.name)).toEqual( + expect.arrayContaining(uiComponentNames()), + ); + expect(catalog.components.map((component) => component.name).sort()).toEqual( + uiComponentNames().sort(), + ); + expect(reference.components.find((component) => component.name === "Button")?.props).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "label" }), + expect.objectContaining({ name: "as" }), + ]), + ); + expect( + reference.components + .find((component) => component.name === "PinInput") + ?.props.find((prop) => prop.name === "length"), + ).toEqual(expect.objectContaining({ default: "4" })); +}); + +test("interactive components expose their must-have public event contracts", () => { + const reference = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-reference.json"), "utf8"), + ) as { components: Array<{ name: string; events: string[] }> }; + const eventsByComponent = new Map( + reference.components.map((component) => [component.name, component.events]), + ); + const requiredEvents: Record = { + Button: ["click", "focus", "blur"], + Input: ["input", "change", "focus", "blur", "invalid"], + Select: ["input", "change", "open", "close"], + Checkbox: ["input", "change", "focus", "blur", "invalid"], + ColorPicker: ["input", "change", "focus", "blur"], + FileInput: ["input", "change", "focus", "blur", "select", "clear", "invalid"], + InputGroup: ["input", "change", "focus", "blur", "submit", "action"], + Radio: ["input", "change", "focus", "blur", "invalid"], + RangeSlider: ["input", "change", "focus", "blur"], + Switch: ["input", "change", "focus", "blur"], + Textarea: ["input", "change", "focus", "blur", "invalid"], + TimePicker: ["input", "change", "focus", "blur", "open", "close", "invalid"], + Accordion: ["change", "open", "close"], + Modal: ["open", "close", "cancel", "confirm"], + DataTable: ["sort", "select", "change", "rowClick", "pageChange"], + FileUpload: ["select", "upload", "progress", "success", "error", "cancel", "remove"], + WysiwygEditor: ["input", "change", "focus", "blur"], + }; + + for (const [component, events] of Object.entries(requiredEvents)) { + expect(eventsByComponent.get(component)).toEqual(expect.arrayContaining(events)); + } +}); + +test("component reference contains only explicitly declared public events", () => { + const reference = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-reference.json"), "utf8"), + ) as { components: Array<{ name: string; events: string[] }> }; + + for (const component of reference.components) { + const source = readFileSync(uiComponentPath(component.name), "utf8"); + const declaredEvents = [ + ...source.matchAll(/@event\s+([A-Za-z][A-Za-z0-9_]*)\s*=\s*function/g), + ].map((match) => match[1]); + expect(component.events).toEqual([...new Set(declaredEvents)]); + } +}); + +test("bundled components do not duplicate another component implementation", () => { + const implementations = new Map(); + + for (const name of uiComponentNames()) { + const source = readFileSync(uiComponentPath(name), "utf8") + .replace(/^component\s+[A-Za-z0-9_]+/, "component __NAME__") + .replace(/\r\n/g, "\n") + .trim(); + expect(implementations.get(source)).toBeUndefined(); + implementations.set(source, name); + } +}); + +test("removed duplicate aliases have valid canonical migration targets", () => { + const migration = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-migrations.json"), "utf8"), + ) as { removedCount: number; replacements: Record }; + const names = new Set(uiComponentNames()); + + expect(Object.keys(migration.replacements)).toHaveLength(migration.removedCount); + expect(migration.removedCount).toBe(0); + for (const [removed, replacement] of Object.entries(migration.replacements)) { + expect(names.has(removed)).toBe(false); + expect(names.has(replacement)).toBe(true); + } +}); + +test("screenshot-directed canonical components are bundled", () => { + const required = [ + "Container", + "Columns", + "Grid", + "Typography", + "Button", + "Accordion", + "Alert", + "Avatar", + "Card", + "Carousel", + "DatePicker", + "Progress", + "Spinner", + "Timeline", + "Navbar", + "Tabs", + "Sidebar", + "Breadcrumb", + "Pagination", + "Stepper", + "Input", + "Textarea", + "Checkbox", + "Radio", + "Switch", + "Select", + "ComboBox", + "TimePicker", + "Modal", + "Drawer", + "Popover", + "Tooltip", + "Table", + "DataTable", + "Chart", + "FileUpload", + "Map", + "WysiwygEditor", + ]; + + expect(uiComponentNames()).toEqual(expect.arrayContaining(required)); +}); + +test("navbar supports brands, nested menus, actions, utility slots, and public events", () => { + const source = readFileSync(uiComponentPath("Navbar"), "utf8"); + expect(source).toContain('slot name="topbar"'); + expect(source).toContain('slot name="actions"'); + expect(source).toContain("brand = {}"); + expect(source).toContain("actions = []"); + expect(source).toContain("openOnHover = false"); + expect(source).toContain('maxWidth = "full"'); + expect(source).toContain("item.children"); + expect(source).toContain("child.children"); + expect(source).toContain("wire-navbar__dropdown--{item.type || 'dropdown'}"); + for (const event of ["toggle", "open", "close", "select", "action"]) { + expect(source).toContain(`@event ${event} = function`); + } +}); + +test("auth form uses package schemas, disables native validation, and renders a full-width submit control", async () => { + const source = readFileSync(uiComponentPath("AuthForm"), "utf8"); + expect(source).toContain('return "auth-login"'); + expect(source).toContain('data-schema="{schemaName()}"'); + expect(source).toContain('data-wrnexus-runtime="auth"'); + expect(source).toContain('novalidate="true"'); + expect(source).toContain('fullWidth="true"'); + + const html = await renderComponent(source, { mode: "sign-in" }); + expect(html).toContain('data-schema="auth-login"'); + expect(html).toContain('data-wrnexus-runtime="auth"'); + expect(html).toContain("novalidate"); + expect(html).toContain("wire-auth-form__submit"); + expect(html).toContain('fullWidth="true"'); +}); + +test("footer supports typed entries, responsive columns, pre/post slots, and events", () => { + const source = readFileSync(uiComponentPath("Footer"), "utf8"); + expect(source).toContain('slot name="pre-footer"'); + expect(source).toContain('slot name="post-footer"'); + expect(source).toContain('slot name="copyright-left"'); + expect(source).toContain('slot name="copyright-right"'); + expect(source).toContain('item.type === "header"'); + expect(source).toContain("wire-footer--columns-{columns}"); + expect(source).toContain("@event select = function"); + expect(source).toContain("@event action = function"); +}); + +test("navbar renders a brand, nested dropdowns, mega groups, and actions", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Navbar"), "utf8"), { + brand: { + label: "Police Management System", + description: "Public portal", + href: "/", + }, + items: [ + { + label: "Services", + type: "dropdown", + children: [{ label: "Reports", href: "/reports" }], + }, + { + label: "Safety", + type: "mega", + columns: 2, + children: [ + { + label: "Resources", + children: [{ label: "Guidance", href: "/guidance" }], + }, + ], + }, + ], + actions: [{ label: "Sign in", href: "/login", variant: "primary" }], + }); + + expect(html).toContain("Police Management System"); + expect(html).toContain("Public portal"); + expect(html).toContain("Reports"); + expect(html).toContain("Guidance"); + expect(html).toContain("wire-navbar__dropdown--mega"); + expect(html).toContain("data-wrn-navbar"); + expect(html).toContain('name="wire-navbar-menu"'); + expect(html).toContain("Sign in"); +}); + +test("navbar closes sibling menus and menus close after an outside pointer press", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Navbar"), "utf8"), { + items: [ + { label: "Services", children: [{ label: "Reports", href: "/reports" }] }, + { label: "Safety", children: [{ label: "Guidance", href: "/guidance" }] }, + ], + }); + const dom = mountHtml(html); + const menus = Array.from(dom.querySelectorAll(".wire-navbar__dropdown")) as HTMLDetailsElement[]; + + menus[0].open = true; + menus[0].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("toggle", { bubbles: false }), + ); + menus[1].open = true; + menus[1].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("toggle", { bubbles: false }), + ); + expect(menus[0].open).toBe(false); + expect(menus[1].open).toBe(true); + + dom.document.body.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("pointerdown", { bubbles: true }), + ); + expect(menus[1].open).toBe(false); +}); + +test("navbar optionally opens menus on hover and renders full-width mode", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Navbar"), "utf8"), { + openOnHover: true, + maxWidth: "full", + items: [{ label: "Services", children: [{ label: "Reports", href: "/reports" }] }], + }); + const dom = mountHtml(html); + const navbar = dom.querySelector("[data-wrn-navbar]"); + const menu = dom.querySelector(".wire-navbar__dropdown") as HTMLDetailsElement; + + expect(navbar?.classList.contains("wire-navbar--width-full")).toBe(true); + expect(navbar?.getAttribute("data-open-on-hover")).toBe("true"); + menu.dispatchEvent(new (dom.window as { Event: typeof Event }).Event("pointerenter")); + expect(menu.open).toBe(true); + menu.dispatchEvent(new (dom.window as { Event: typeof Event }).Event("pointerleave")); + expect(menu.open).toBe(true); + await new Promise((resolve) => setTimeout(resolve, 280)); + expect(menu.open).toBe(false); +}); + +test("navbar hover menu stays open while the pointer crosses into its panel", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Navbar"), "utf8"), { + openOnHover: true, + items: [{ label: "Services", children: [{ label: "Reports", href: "/reports" }] }], + }); + const dom = mountHtml(html); + const menu = dom.querySelector(".wire-navbar__dropdown") as HTMLDetailsElement; + const panel = dom.querySelector(".wire-navbar__panel") as HTMLElement; + const DomEvent = (dom.window as { Event: typeof Event }).Event; + + menu.dispatchEvent(new DomEvent("pointerenter")); + menu.dispatchEvent(new DomEvent("pointerleave")); + panel.dispatchEvent(new DomEvent("pointerenter", { bubbles: true })); + await new Promise((resolve) => setTimeout(resolve, 280)); + + expect(menu.open).toBe(true); +}); + +test("preference switcher keeps only one popover open and closes outside", async () => { + const html = await renderComponent( + readFileSync(uiComponentPath("PreferenceSwitcher"), "utf8"), + {}, + ); + const dom = mountHtml(html); + const menus = Array.from(dom.querySelectorAll(".wire-preferences__menu")) as HTMLDetailsElement[]; + const DomEvent = (dom.window as { Event: typeof Event }).Event; + + menus[0].open = true; + menus[0].dispatchEvent(new DomEvent("toggle")); + menus[1].open = true; + menus[1].dispatchEvent(new DomEvent("toggle")); + expect(menus[0].open).toBe(false); + expect(menus[1].open).toBe(true); + + dom.document.body.dispatchEvent(new DomEvent("pointerdown", { bubbles: true })); + expect(menus[1].open).toBe(false); +}); + +test("sidebar renders compact grouped submenu navigation and a mobile drawer trigger", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Sidebar"), "utf8"), { + label: "Operations", + orientation: "vertical", + items: [ + { label: "Dashboard", href: "/dashboard", value: "dashboard" }, + { + label: "Case management", + children: [ + { label: "Assigned cases", href: "/cases", value: "cases" }, + { label: "Evidence", href: "/evidence", value: "evidence" }, + ], + }, + ], + }); + + expect(html).toContain("wire-sidebar-toggle"); + expect(html).toContain("wire-sidebar-backdrop"); + expect(html).toContain("wire-sidebar-group"); + expect(html).toContain("Assigned cases"); + expect(html).toContain("Evidence"); +}); + +test("dropdown renders slotted account triggers, menu structure, and public events", async () => { + const source = readFileSync(uiComponentPath("Dropdown"), "utf8"); + const html = await renderComponent(source, { + label: "Account menu", + items: [ + { type: "header", label: "Account" }, + { label: "Profile", href: "/profile", icon: "icon-[lucide--user]" }, + { type: "divider" }, + { label: "Sign out", href: "/logout", danger: true }, + ], + }); + + expect(source).toContain('slot name="trigger"'); + expect(source).toContain("@event select = function"); + expect(html).toContain("wire-dropdown__panel"); + expect(html).toContain("Profile"); + expect(html).toContain("wire-dropdown__item--danger"); +}); + +test("footer renders header and link entries with the requested column count", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Footer"), "utf8"), { + columns: 4, + items: [ + { type: "header", label: "Support" }, + { type: "link", label: "Contact", href: "/contact" }, + ], + copyright: "Public service platform", + }); + + expect(html).toContain("wire-footer--columns-4"); + expect(html).toContain("wire-footer__column"); + expect(html).toContain("wire-footer__column-links"); + expect(html).toContain("wire-footer__heading"); + expect(html).toContain("Support"); + expect(html).toContain('href="/contact"'); + expect(html).toContain("Public service platform"); +}); + +test("component-system CSS includes responsive, theme-token, focus, and reduced-motion rules", () => { + const css = uiCss(); + expect(css).toContain("@media (max-width: 768px)"); + expect(css).toContain("@media (max-width: 480px)"); + expect(css).toContain("@media (prefers-reduced-motion: reduce)"); + expect(css).toContain(":focus-visible"); + expect(css).toContain("var(--wire-color-surface)"); + expect(css).toContain("min-height: 44px"); + expect(css).toContain("--wire-motion-base"); + expect(css).toContain("--wire-ease-emphasized"); + expect(css).toContain("@keyframes wire-component-enter"); + expect(css).toContain("@keyframes wire-dialog-enter"); + expect(css).toContain("@media (hover: hover) and (pointer: fine)"); + expect(css).toContain("--color-violet-600: var(--wire-color-primary)"); + expect(css).toContain("--color-blue-600: var(--wire-color-info)"); + expect(css).toContain("--color-red-600: var(--wire-color-danger)"); + expect(css).toMatch(/:root\s*\{[^}]*--color-violet-600: var\(--wire-color-primary\)/s); + expect(css).toContain(".wire-bg-primary"); + expect(css).toContain(".wire-text-muted"); + expect(css).toContain(".wire-visually-hidden"); + expect(css).toContain(".wire-next--field"); + expect(css).toContain(".wire-next--table"); + expect(css).toContain('[data-show="false"]'); + expect(css).toContain("display: none !important"); + expect(css).toMatch( + /\.wire-navbar__brand-copy strong\s*\{[^}]*font-size: 0\.9rem;[^}]*font-weight: 600;/s, + ); + expect(css).toMatch( + /\.wire-navbar__menu-link,[\s\S]*?font-size: 0\.8125rem;[\s\S]*?font-weight: 500;/, + ); + expect(css).toMatch( + /\.wire-footer__heading\s*\{[^}]*font-size: 0\.8125rem;[^}]*font-weight: 600;/s, + ); + expect(css).toMatch(/\.wire-footer__link\s*\{[^}]*font-size: 0\.8125rem;[^}]*font-weight: 400;/s); +}); + +test("component boundaries have no default margins and expose the canonical class prop", () => { + for (const name of uiComponentNames()) { + const source = readFileSync(uiComponentPath(name), "utf8"); + const root = source.match(/view\s*\{\s*<[A-Za-z][^>]*>/)?.[0] ?? ""; + const classes = root.match(/\bclass="([^"]*)"/)?.[1]?.split(/\s+/) ?? []; + expect(classes.filter((token) => /^-?m[trblxy]?-/.test(token))).toEqual([]); + expect(source).toMatch(/^\s*class\s*(?::[^=\r\n]+)?=/m); + expect(source).not.toMatch(/^\s*className\s*(?::[^=\r\n]+)?=/m); + expect(root).toContain("{class}"); + } +}); + +test("every component exposes universal color and size configuration", () => { + for (const name of uiComponentNames()) { + const source = readFileSync(uiComponentPath(name), "utf8"); + expect(source).toMatch(/^\s+color\s*=/m); + expect(source).toMatch(/^\s+size\s*=/m); + } +}); + +// test("component markup keeps user-facing content and data behind props", () => { +// for (const name of uiComponentNames()) { +// const source = readFileSync(uiComponentPath(name), "utf8"); +// const view = source.slice(source.indexOf("view {")); +// const literalText = [...view.matchAll(/>([^<>{}]*[A-Za-z][^<>{}]*) match[1].trim()) +// .filter(Boolean); +// const literalAccessibleText = [ +// ...view.matchAll(/\b(?:aria-label|title|placeholder|alt)="([^"{}]*[A-Za-z][^"{}]*)"/g), +// ]; +// const literalDataAttributes = [ +// ...view.matchAll(/\b(?:href|src|action|value)="([^"{}]+)"/g), +// ].filter((match) => !/^(?:true|false|on)$/.test(match[1])); + +// expect(literalText).toEqual([]); +// expect(literalAccessibleText).toEqual([]); +// expect(literalDataAttributes).toEqual([]); +// } +// }); + +test("layout boundaries do not add default padding", () => { + for (const name of ["Container", "Columns", "Grid", "LayoutSplitter", "Typography"]) { + const source = readFileSync(uiComponentPath(name), "utf8"); + const root = source.match(/view\s*\{\s*<[A-Za-z][^>]*>/)?.[0] ?? ""; + const classes = root.match(/\bclass="([^"]*)"/)?.[1]?.split(/\s+/) ?? []; + expect(classes.filter((token) => /^p[trblxy]?-/.test(token))).toEqual([]); + } +}); + +test("every bundled UI component compiles", () => { + for (const name of uiComponentNames()) { + const path = uiComponentPath(name); + expect(() => compileWireFile(readFileSync(path, "utf8"), path)).not.toThrow(); + } +}); + +test("icon buttons expose their accessible label as a hover and focus tooltip", () => { + const button = readFileSync(uiComponentPath("Button"), "utf8"); + expect(button).toContain('class="wire-btn__tooltip"'); + expect(button).toContain("{ariaLabel || label}"); + expect(uiCss()).toContain(".wire-btn:hover > .wire-btn__tooltip"); + expect(uiCss()).toContain(".wire-btn:focus-visible > .wire-btn__tooltip"); +}); + +test("button links navigate by default and only download when the native attribute is passed", () => { + const button = readFileSync(uiComponentPath("Button"), "utf8"); + expect(button).not.toMatch(/^\s+download\s*=/m); + expect(button).not.toContain('download="{download}"'); + expect(button).toContain("{...attrs}"); +}); + +test("button group renders connected actions and emits select and change events", async () => { + const source = readFileSync(uiComponentPath("ButtonGroup"), "utf8"); + const html = await renderComponent(source, { + items: [ + { label: "Profile", value: "profile" }, + { label: "Settings", value: "settings" }, + { label: "Messages", value: "messages", disabled: true }, + ], + value: "profile", + selectable: true, + size: "sm", + variant: "outline", + ariaLabel: "Account views", + }); + const dom = mountHtml(html); + const group = dom.querySelector(".wire-next--button-group") as HTMLElement; + const buttons = [...dom.querySelectorAll(".wire-next--button-group > button")]; + const events: Array<{ name: string; detail: unknown }> = []; + + for (const name of ["select", "change"]) { + group.addEventListener(name, (event) => + events.push({ name, detail: (event as CustomEvent).detail }), + ); + } + + expect(group.getAttribute("role")).toBe("group"); + expect(group.getAttribute("aria-label")).toBe("Account views"); + expect(group.getAttribute("data-size")).toBe("sm"); + expect(buttons).toHaveLength(3); + expect(buttons[0]?.getAttribute("aria-pressed")).toBe("true"); + expect(buttons[2]?.hasAttribute("disabled")).toBe(true); + + (buttons[1] as HTMLButtonElement).click(); + + expect(buttons[0]?.getAttribute("aria-pressed")).toBe("false"); + expect(buttons[1]?.getAttribute("aria-pressed")).toBe("true"); + expect(events.map((event) => event.name)).toEqual(["select", "change"]); + expect((events[1]?.detail as { value: string }).value).toBe("settings"); + expect((events[1]?.detail as { previousValue: string }).previousValue).toBe("profile"); +}); + +test("button group supports vertical, responsive, detached, and toolbar layouts", async () => { + const source = readFileSync(uiComponentPath("ButtonGroup"), "utf8"); + const html = await renderComponent(source, { + items: [{ label: "Bold", icon: "icon-[lucide--bold]" }], + orientation: "vertical", + responsive: true, + attached: false, + toolbar: true, + ariaLabel: "Formatting", + }); + const dom = mountHtml(html); + const group = dom.querySelector(".wire-next--button-group") as HTMLElement; + + expect(group.getAttribute("role")).toBe("toolbar"); + expect(group.getAttribute("aria-orientation")).toBe("vertical"); + expect(group.getAttribute("data-responsive")).toBe("true"); + expect(group.getAttribute("data-attached")).toBe("false"); + expect(group.querySelector('[class*="icon-[lucide--bold]"]')).not.toBeNull(); + + const css = uiCss(); + expect(css).toContain('.wire-next--button-group[data-orientation="vertical"]'); + expect(css).toContain('.wire-next--button-group[data-responsive="true"]'); + expect(css).toContain('.wire-next--button-group[data-attached="false"]'); +}); + +test("every bundled UI component forwards undeclared native attributes", () => { + for (const name of uiComponentNames()) { + const path = uiComponentPath(name); + const output = compileWireFile(readFileSync(path, "utf8"), path); + expect(output).toContain("${__wireSpreadAttrs(__attrs)}"); + } +}); + +test("accordion coordinates single-open sections and emits open, close, and change events", async () => { + const source = readFileSync(uiComponentPath("Accordion"), "utf8"); + const html = await renderComponent(source, { + id: "faq", + defaultOpen: ["first"], + items: [ + { value: "first", label: "First", content: "First content" }, + { value: "second", label: "Second", content: "Second content" }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-accordion]") as HTMLElement; + const events: string[] = []; + for (const name of ["open", "close", "change"]) { + root.addEventListener(name, () => events.push(name)); + } + + expect(dom.querySelector("#faq-trigger-0")?.getAttribute("aria-expanded")).toBe("true"); + expect(dom.querySelector("#faq-panel-0")?.getAttribute("aria-hidden")).toBe("false"); + + (dom.querySelector("#faq-trigger-1") as HTMLButtonElement).click(); + + expect(dom.querySelector("#faq-trigger-0")?.getAttribute("aria-expanded")).toBe("false"); + expect(dom.querySelector("#faq-trigger-1")?.getAttribute("aria-expanded")).toBe("true"); + expect(events).toEqual(["open", "change"]); + + (dom.querySelector("#faq-trigger-1") as HTMLButtonElement).click(); + expect(dom.querySelector("#faq-trigger-1")?.getAttribute("aria-expanded")).toBe("false"); + expect(events).toEqual(["open", "change", "close", "change"]); +}); + +test("accordion supports always-open, nested, and disabled sections", async () => { + const source = readFileSync(uiComponentPath("Accordion"), "utf8"); + const html = await renderComponent(source, { + id: "nested-faq", + alwaysOpen: true, + defaultOpen: ["first", "first.child"], + items: [ + { + value: "first", + label: "First", + content: "First content", + children: [{ value: "child", label: "Child", content: "Child content" }], + }, + { value: "second", label: "Second", content: "Second content" }, + { value: "third", label: "Third", content: "Third content", disabled: true }, + ], + }); + const dom = mountHtml(html); + + expect(dom.querySelector("#nested-faq-trigger-0")?.getAttribute("aria-expanded")).toBe("true"); + expect(dom.querySelector("#nested-faq-trigger-0-0")?.getAttribute("aria-expanded")).toBe("true"); + + (dom.querySelector("#nested-faq-trigger-1") as HTMLButtonElement).click(); + expect(dom.querySelector("#nested-faq-trigger-0")?.getAttribute("aria-expanded")).toBe("true"); + expect(dom.querySelector("#nested-faq-trigger-1")?.getAttribute("aria-expanded")).toBe("true"); + expect((dom.querySelector("#nested-faq-trigger-2") as HTMLButtonElement).disabled).toBe(true); +}); + +test("accordion chevrons use a consistent icon instead of a font glyph", () => { + const source = readFileSync(uiComponentPath("Accordion"), "utf8"); + + expect(source).toContain("icon-[lucide--chevron-down]"); + expect(source).not.toContain('return "⌄"'); +}); + +test("alert renders structured content, lists, actions, and accessible semantics", async () => { + const source = readFileSync(uiComponentPath("Alert"), "utf8"); + const html = await renderComponent(source, { + title: "Cannot save changes", + description: "Review the following fields.", + color: "danger", + variant: "soft", + showIcon: true, + items: [{ label: "Email is required" }, { label: "Phone number is invalid" }], + actions: [{ label: "Review form", href: "#form" }], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-alert]") as HTMLElement; + let detail: Record | undefined; + root.addEventListener("action", (event) => { + detail = (event as unknown as CustomEvent>).detail; + }); + + expect(root.getAttribute("role")).toBe("alert"); + expect(root.getAttribute("aria-live")).toBe("polite"); + expect(root.dataset.color).toBe("danger"); + expect(dom.querySelectorAll(".wire-next__alert-body li").map((node) => node.textContent)).toEqual( + ["Email is required", "Phone number is invalid"], + ); + + (dom.querySelector(".wire-next__alert-actions a") as HTMLAnchorElement).click(); + expect(detail).toMatchObject({ + component: "Alert", + action: { label: "Review form", href: "#form" }, + }); +}); + +test("dismissible alert hides itself and emits dismiss details", async () => { + const source = readFileSync(uiComponentPath("Alert"), "utf8"); + const html = await renderComponent(source, { + title: "Update available", + description: "Install the latest version.", + dismissible: true, + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-alert]") as HTMLElement; + let dismissed = false; + root.addEventListener("dismiss", () => { + dismissed = true; + }); + + (dom.querySelector(".wire-next__alert-dismiss") as HTMLButtonElement).click(); + + expect(dismissed).toBe(true); + expect(root.getAttribute("aria-hidden")).toBe("true"); + expect(root.style.display).toBe("none"); +}); + +test("solid alert palettes preserve readable foregrounds and compact inline layout", () => { + const css = uiCss(); + + expect(css).toContain('.wire-next--alert[data-color="secondary"]'); + expect(css).toContain("--wire-alert-color: #737373"); + expect(css).toContain( + ".wire-next--alert-compact:not(:has(.wire-next__alert-icon)):not(:has(.wire-next__alert-dismiss))", + ); + expect(css).toContain(".wire-next--alert-compact .wire-next__alert-body > p"); + expect(css).toContain("color: currentColor"); +}); + +test("alert exposes configurable radius and elevation treatments", async () => { + const source = readFileSync(uiComponentPath("Alert"), "utf8"); + const html = await renderComponent(source, { + title: "Elevated alert", + radius: "xl", + shadow: "lg", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-alert]") as HTMLElement; + const css = uiCss(); + + expect(root.dataset.radius).toBe("xl"); + expect(root.dataset.shadow).toBe("lg"); + expect(css).toContain('.wire-next--alert[data-radius="xl"]'); + expect(css).toContain('.wire-next--alert[data-shadow="lg"]'); + expect(css).toContain("border-radius: calc(var(--wire-radius, 0.75rem) * 1.75)"); + expect(css).toContain("0 20px 48px color-mix(in srgb, #000 24%, transparent)"); +}); + +test("avatar renders images, fallbacks, presence, badges, tooltips, and media copy", async () => { + const source = readFileSync(uiComponentPath("Avatar"), "utf8"); + const imageHtml = await renderComponent(source, { + src: "/avatar.jpg", + alt: "Avery Chen", + shape: "rounded", + statusPosition: "top", + status: "online", + statusLabel: "Online", + tooltip: "Avery Chen · Online", + }); + const imageDom = mountHtml(imageHtml); + const imageRoot = imageDom.querySelector("[data-wrn-avatar]") as HTMLElement; + + expect(imageRoot.querySelector('img[alt="Avery Chen"]')).not.toBeNull(); + expect(imageRoot.querySelector('[data-status="online"]')?.getAttribute("aria-label")).toBe( + "Online", + ); + expect(imageRoot.querySelector('[role="tooltip"]')?.textContent).toContain("Avery Chen"); + + const initialsDom = mountHtml( + await renderComponent(source, { + initials: "MW", + color: "success", + badgeIcon: "icon-[lucide--message-square]", + badgeLabel: "Messaging account", + name: "Mark Wanner", + description: "mark@example.com", + }), + ); + expect(initialsDom.querySelector(".wire-next__avatar-initials")?.textContent).toBe("MW"); + expect(initialsDom.querySelector(".wire-next__avatar-badge")?.getAttribute("aria-label")).toBe( + "Messaging account", + ); + expect(initialsDom.querySelector(".wire-next__avatar-copy")?.textContent).toContain( + "mark@example.com", + ); + + const placeholderDom = mountHtml(await renderComponent(source, { size: "sm" })); + expect(placeholderDom.querySelector(".wire-next__avatar-placeholder")).not.toBeNull(); + expect(source).not.toContain("items ="); + expect(uiCss()).toContain('.wire-next__avatar-wrap[data-shape="rounded"]'); +}); + +test("avatar group limits members and opens an accessible overflow menu", async () => { + const source = readFileSync(uiComponentPath("AvatarGroup"), "utf8"); + const html = await renderComponent(source, { + maxVisible: 2, + borderColor: "#2583ff", + items: [ + { src: "/one.svg", name: "One" }, + { initials: "TW", name: "Two" }, + { initials: "TH", name: "Three" }, + { initials: "FO", name: "Four" }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-avatar-group]") as HTMLElement; + const button = root.querySelector( + ".wire-next__avatar-group-overflow-button", + ) as HTMLButtonElement; + let eventDetail: { open: boolean; hiddenCount: number } | undefined; + root.addEventListener("overflow", (event) => { + eventDetail = (event as CustomEvent).detail; + }); + + expect(root.querySelectorAll(".wire-next__avatar-group-member")).toHaveLength(2); + expect(button.textContent?.trim()).toBe("+2"); + expect(button.getAttribute("aria-expanded")).toBe("false"); + expect(root.getAttribute("style")).toContain("#2583ff"); + expect(root.querySelector(".wire-next__avatar-group-menu")?.getAttribute("data-show")).toBe( + "false", + ); + + button.click(); + + expect( + dom.querySelector(".wire-next__avatar-group-overflow-button")?.getAttribute("aria-expanded"), + ).toBe("true"); + expect(dom.querySelectorAll('[role="menuitem"]')).toHaveLength(2); + expect(dom.querySelector(".wire-next__avatar-group-menu")?.getAttribute("data-show")).toBe( + "true", + ); + expect(eventDetail).toEqual(expect.objectContaining({ open: true, hiddenCount: 2 })); + expect(uiCss()).toContain('.wire-next--avatar-group[data-layout="grid"]'); +}); + +test("badge supports rich content, anchored placement, animation, and dismissal", async () => { + const source = readFileSync(uiComponentPath("Badge"), "utf8"); + const html = await renderComponent(source, { + label: "Christina", + color: "success", + variant: "soft", + icon: "icon-[lucide--circle-check]", + dot: true, + avatarSrc: "/avatar.svg", + avatarAlt: "Christina", + dismissible: true, + animated: true, + anchorIcon: "icon-[lucide--bell]", + anchorLabelText: "Open notifications", + placement: "top-right", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-badge]") as HTMLElement; + let dismissed = ""; + root.addEventListener("dismiss", (event) => { + dismissed = (event as CustomEvent).detail.label; + }); + + expect(root.dataset.placement).toBe("top-right"); + expect(root.querySelector(".wire-next__badge-anchor")?.getAttribute("aria-label")).toBe( + "Open notifications", + ); + expect(root.querySelector('img[alt="Christina"]')).not.toBeNull(); + expect(root.querySelector(".wire-next__badge-dot")).not.toBeNull(); + expect(root.querySelector(".wire-next__badge-ping")).not.toBeNull(); + + (root.querySelector(".wire-next__badge-dismiss") as HTMLButtonElement).click(); + + expect(dom.querySelector("[data-wrn-badge]")?.getAttribute("data-show")).toBe("false"); + expect(dismissed).toBe("Christina"); + expect(source).not.toContain("items ="); + expect(uiCss()).toContain("@keyframes wire-badge-ping"); +}); + +test("blockquote renders semantic quote and citation content", async () => { + const source = readFileSync(uiComponentPath("Blockquote"), "utf8"); + const html = await renderComponent(source, { + quote: "Design is intelligence made visible.", + citation: "Alina Wheeler", + citationTitle: "Author, Designing Brand Identity", + citationUrl: "https://example.com/source", + avatarSrc: "/authors/alina.jpg", + avatarAlt: "Alina Wheeler", + size: "lg", + color: "info", + align: "center", + }); + const dom = mountHtml(html); + const figure = dom.querySelector("figure") as HTMLElement; + const quote = figure.querySelector("blockquote"); + const citation = figure.querySelector("figcaption"); + + expect(figure.getAttribute("data-size")).toBe("lg"); + expect(figure.getAttribute("data-color")).toBe("info"); + expect(figure.getAttribute("data-align")).toBe("center"); + expect(quote?.getAttribute("cite")).toBe("https://example.com/source"); + expect(quote?.textContent).toContain("Design is intelligence made visible."); + expect(quote?.querySelector('[aria-hidden="true"]')?.textContent).toBe("“"); + expect(citation?.querySelector("cite a")?.textContent).toBe("Alina Wheeler"); + expect(citation?.textContent).toContain("Author, Designing Brand Identity"); + expect(citation?.querySelector("img")?.getAttribute("alt")).toBe("Alina Wheeler"); +}); + +test("blockquote supports bordered, right-aligned, non-italic, and slotted quotes", async () => { + const source = readFileSync(uiComponentPath("Blockquote"), "utf8"); + const html = await renderComponent(source, { + quote: "", + variant: "bordered", + align: "right", + italic: false, + quoteMark: false, + }); + const dom = mountHtml(html); + const figure = dom.querySelector("figure") as HTMLElement; + + expect(figure.getAttribute("data-variant")).toBe("bordered"); + expect(figure.getAttribute("data-align")).toBe("right"); + expect(figure.getAttribute("data-italic")).toBe("false"); + expect(figure.querySelector(".wire-next__blockquote-mark")).toBeNull(); + expect(source).toContain(""); + + const css = uiCss(); + expect(css).toContain('.wire-next--blockquote[data-variant="bordered"]'); + expect(css).toContain('.wire-next--blockquote[data-align="center"]'); + expect(css).toContain("--wire-blockquote-font-size"); +}); + +test("card renders structured media, header, body, action, and footer content", async () => { + const source = readFileSync(uiComponentPath("Card"), "utf8"); + const html = await renderComponent(source, { + title: "Release notes", + subtitle: "Version 2.4", + description: "A structured card description.", + header: "Featured", + footer: "Updated today", + imageSrc: "/release.jpg", + imageAlt: "Release preview", + actionLabel: "Read more", + actionHref: "/releases/2-4", + size: "lg", + color: "info", + }); + const dom = mountHtml(html); + const card = dom.querySelector(".wire-next--card") as HTMLElement; + + expect(card.getAttribute("data-size")).toBe("lg"); + expect(card.getAttribute("data-color")).toBe("info"); + expect(card.querySelector("article")).not.toBeNull(); + expect(card.querySelector("header")?.textContent).toContain("Featured"); + expect(card.querySelector("img")?.getAttribute("alt")).toBe("Release preview"); + expect(card.querySelector("h3")?.textContent).toBe("Release notes"); + expect(card.querySelector(".wire-next__card-subtitle")?.textContent).toBe("Version 2.4"); + expect(card.querySelector(".wire-next__card-action")?.getAttribute("href")).toBe("/releases/2-4"); + expect(card.querySelector("footer")?.textContent).toContain("Updated today"); +}); + +test("card navigation, header actions, and dismissal emit public events", async () => { + const source = readFileSync(uiComponentPath("Card"), "utf8"); + const html = await renderComponent(source, { + title: "Account", + header: "Card actions", + navigation: [ + { label: "Profile", value: "profile" }, + { label: "Security", value: "security" }, + ], + activeNav: "profile", + headerActions: [{ label: "Refresh", icon: "icon-[lucide--refresh-cw]" }], + dismissible: true, + }); + const dom = mountHtml(html); + const card = dom.querySelector(".wire-next--card") as HTMLElement; + const events: string[] = []; + + for (const name of ["navigate", "action", "dismiss"]) { + card.addEventListener(name, () => events.push(name)); + } + + (dom.querySelectorAll(".wire-next__card-tabs button")[1] as HTMLButtonElement).click(); + (dom.querySelector(".wire-next__card-header-actions button") as HTMLButtonElement).click(); + (dom.querySelectorAll(".wire-next__card-header-actions button")[1] as HTMLButtonElement).click(); + + expect(events).toEqual(["navigate", "action", "dismiss"]); + expect(dom.querySelector(".wire-next__card-panel")?.hasAttribute("hidden")).toBe(true); +}); + +test("card supports overlays, horizontal media, groups, alerts, empty and scrolling panels", async () => { + const source = readFileSync(uiComponentPath("Card"), "utf8"); + const overlay = mountHtml( + await renderComponent(source, { + title: "Overlay", + description: "Overlay copy", + imageSrc: "/overlay.jpg", + imagePosition: "overlay", + }), + ); + const group = mountHtml( + await renderComponent(source, { + items: [ + { title: "First", description: "First card" }, + { title: "Second", description: "Second card" }, + ], + }), + ); + const panel = mountHtml( + await renderComponent(source, { + title: "", + alertTitle: "Attention", + alertDescription: "Review this state.", + empty: true, + scrollable: true, + maxHeight: "12rem", + }), + ); + + expect(overlay.querySelector(".wire-next__card-overlay")).not.toBeNull(); + expect(group.querySelectorAll(".wire-next__card-group > article")).toHaveLength(2); + expect(panel.querySelector(".wire-next__card-alert")?.getAttribute("role")).toBe("status"); + expect(panel.querySelector(".wire-next__card-empty")?.textContent).toContain("No data to show"); + expect(panel.querySelector(".wire-next__card-body")?.getAttribute("data-scrollable")).toBe( + "true", + ); + + const css = uiCss(); + expect(css).toContain('.wire-next--card[data-layout="horizontal"]'); + expect(css).toContain('.wire-next--card[data-hover="image"]'); + expect(css).toContain(".wire-next__card-group"); + expect(css).toContain(".wire-next__card-navigation-select"); + expect(css).toContain("aspect-ratio: 16 / 9"); + expect(css).toContain("rgb(2 6 23 / 0.86)"); +}); + +test("chat bubble renders conversations, avatars, metadata, links, and public events", async () => { + const source = readFileSync(uiComponentPath("ChatBubble"), "utf8"); + const events: string[] = []; + const dom = mountHtml( + await renderComponent(source, { + ariaLabel: "Support conversation", + oneSided: true, + showAvatars: true, + showMetadata: true, + items: [ + { + direction: "incoming", + author: "Support", + avatarFallback: "SP", + title: "How can we help?", + text: "Choose a guide.", + bullets: ["Installation", "Components"], + links: [{ label: "Installation guide", href: "/installation" }], + status: "Sent", + timestamp: "10:32", + }, + { + direction: "outgoing", + text: "Please retry.", + status: "Not sent", + statusTone: "danger", + action: "retry", + actionLabel: "Retry", + }, + ], + }), + ); + + const root = dom.querySelector(".wire-next--chat-bubble") as HTMLElement; + for (const [name, label] of [ + ["messageClick", "message"], + ["avatarClick", "avatar"], + ["linkClick", "link"], + ["action", "action"], + ]) { + root.addEventListener(name, () => events.push(label)); + } + expect(root.getAttribute("role")).toBe("log"); + expect(root.getAttribute("aria-label")).toBe("Support conversation"); + expect(root.dataset.oneSided).toBe("true"); + expect(dom.querySelectorAll(".wire-next__chat-message")).toHaveLength(2); + expect(dom.querySelectorAll(".wire-next__chat-content li")).toHaveLength(2); + expect(dom.querySelector(".wire-next__chat-meta[data-tone='danger']")).not.toBeNull(); + expect(uiCss()).toContain("color: var(--wire-color-primary-contrast, #fff)"); + + (dom.querySelector(".wire-next__chat-content") as HTMLElement).click(); + (dom.querySelector(".wire-next__chat-avatar") as HTMLButtonElement).click(); + (dom.querySelector(".wire-next__chat-content a") as HTMLAnchorElement).click(); + (dom.querySelector(".wire-next__chat-meta button") as HTMLButtonElement).click(); + expect(events).toEqual(["message", "avatar", "link", "action"]); +}); + +test("collapse toggles accessible panels and emits open, close, and toggle events", async () => { + const source = readFileSync(uiComponentPath("Collapse"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + ariaLabel: "Product details", + initialOpenIndexes: [0], + items: [ + { + id: "product-details", + label: "Expand", + closeLabel: "Collapse", + title: "Details", + content: "Additional product information.", + }, + ], + }), + ); + const root = dom.querySelector(".wire-next--collapse") as HTMLElement; + const trigger = dom.querySelector(".wire-next__collapse-trigger") as HTMLButtonElement; + const panel = dom.querySelector(".wire-next__collapse-panel") as HTMLElement; + const events: string[] = []; + for (const name of ["open", "close", "toggle"]) { + root.addEventListener(name, () => events.push(name)); + } + + expect(root.getAttribute("aria-label")).toBe("Product details"); + expect(trigger.getAttribute("aria-expanded")).toBe("true"); + expect(trigger.getAttribute("aria-controls")).toBe("product-details"); + expect(panel.dataset.open).toBe("true"); + expect(panel.getAttribute("aria-hidden")).toBe("false"); + expect(uiCss()).toContain("max-height: 40rem"); + expect(trigger.textContent).toContain("Collapse"); + + trigger.click(); + expect(trigger.getAttribute("aria-expanded")).toBe("false"); + expect(panel.dataset.open).toBe("false"); + expect(panel.getAttribute("aria-hidden")).toBe("true"); + expect(events).toEqual(["close", "toggle"]); + + trigger.click(); + expect(panel.dataset.open).toBe("true"); + expect(events).toEqual(["close", "toggle", "open", "toggle"]); +}); + +test("collapse supports inline read-more and single or multiple open panels", async () => { + const source = readFileSync(uiComponentPath("Collapse"), "utf8"); + const items = [ + { id: "first-collapse", label: "Read more", preview: "First preview", content: "First" }, + { id: "second-collapse", label: "Read more", preview: "Second preview", content: "Second" }, + ]; + const single = mountHtml(await renderComponent(source, { mode: "inline", items })); + const singleTriggers = single.querySelectorAll( + ".wire-next__collapse-trigger", + ) as HTMLButtonElement[]; + singleTriggers[0]?.click(); + singleTriggers[1]?.click(); + expect(singleTriggers[0]?.getAttribute("aria-expanded")).toBe("false"); + expect(singleTriggers[1]?.getAttribute("aria-expanded")).toBe("true"); + expect(single.querySelectorAll(".wire-next__collapse-preview")).toHaveLength(2); + + const multiple = mountHtml(await renderComponent(source, { multiple: true, items })); + const multipleTriggers = multiple.querySelectorAll( + ".wire-next__collapse-trigger", + ) as HTMLButtonElement[]; + multipleTriggers[0]?.click(); + multipleTriggers[1]?.click(); + expect(multipleTriggers[0]?.getAttribute("aria-expanded")).toBe("true"); + expect(multipleTriggers[1]?.getAttribute("aria-expanded")).toBe("true"); +}); + +test("basic form fields expose shared labels, variants, states, hints, values, and validation targets", async () => { + const { checkField } = await import("../../validation/src/index.ts"); + const validation = checkField( + { + type: "string", + optional: false, + trim: true, + rules: [{ kind: "email", message: "Enter a valid email address." }], + }, + "not-an-email", + ); + expect(validation.error).toBe("Enter a valid email address."); + + const source = readFileSync(uiComponentPath("Input"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "account-email", + name: "email", + label: "Email address", + placeholder: "you@example.com", + value: "not-an-email", + type: "email", + variant: "floating", + icon: "icon-[lucide--mail]", + iconPosition: "end", + helperText: "Used for account notices.", + cornerHint: "Required", + error: validation.error, + inline: true, + required: true, + }), + ); + const root = dom.querySelector(".wire-next--input") as HTMLElement; + const input = dom.querySelector("input") as HTMLInputElement; + expect(root.dataset.variant).toBe("floating"); + expect(root.dataset.inline).toBe("true"); + expect(root.dataset.invalid).toBe("true"); + expect(input.id).toBe("account-email"); + expect(input.name).toBe("email"); + expect(input.value).toBe("not-an-email"); + expect(input.getAttribute("aria-invalid")).toBe("true"); + expect(dom.querySelector("[data-error='email']")?.textContent).toContain( + "Enter a valid email address.", + ); + expect(dom.querySelector(".wire-next__field-hint")?.textContent).toContain("Required"); + expect(dom.querySelector(".wire-next__field-icon")).not.toBeNull(); + + const emitted: string[] = []; + for (const name of ["input", "change", "focus", "blur", "keydown", "keyup"]) { + root.addEventListener(name, () => emitted.push(name)); + } + input.dispatchEvent(new (dom.window as any).Event("input", { bubbles: true })); + input.dispatchEvent(new (dom.window as any).Event("change", { bubbles: true })); + input.dispatchEvent(new (dom.window as any).Event("focus", { bubbles: true })); + input.dispatchEvent(new (dom.window as any).Event("blur", { bubbles: true })); + input.dispatchEvent( + new (dom.window as any).KeyboardEvent("keydown", { key: "Enter", bubbles: true }), + ); + input.dispatchEvent( + new (dom.window as any).KeyboardEvent("keyup", { key: "Enter", bubbles: true }), + ); + expect(emitted).toEqual(["input", "change", "focus", "blur", "keydown", "keyup"]); +}); + +test("all basic form components render values and their must-have interaction events", async () => { + const components = [ + "Checkbox", + "ColorPicker", + "FileInput", + "Input", + "InputGroup", + "Radio", + "RangeSlider", + "Select", + "Switch", + "Textarea", + "TimePicker", + ]; + for (const component of components) { + const source = readFileSync(uiComponentPath(component), "utf8"); + const props: Record = { + id: `${component}-field`, + name: `${component}Value`, + label: `${component} label`, + helperText: "Helper text", + cornerHint: "Optional", + error: "", + inline: true, + readonly: true, + disabled: false, + value: component === "RangeSlider" ? 40 : "value", + options: [{ label: "Value", value: "value" }], + }; + const dom = mountHtml(await renderComponent(source, props)); + const control = dom.querySelector("input, textarea, select") as HTMLElement | null; + expect(control).not.toBeNull(); + expect(control?.getAttribute("name")).toBe(`${component}Value`); + expect(dom.querySelector(".wire-next__field-help")?.textContent).toContain("Helper text"); + expect(dom.querySelector(`[data-error="${component}Value"]`)).not.toBeNull(); + } +}); + +test("radio renders passed options in group, card, list, alignment, and description layouts", async () => { + const source = readFileSync(uiComponentPath("Radio"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "plan", + name: "plan", + label: "Choose a plan", + value: "professional", + orientation: "horizontal", + card: true, + list: true, + rightAligned: true, + options: [ + { label: "Starter", value: "starter", description: "For individuals." }, + { label: "Professional", value: "professional", description: "For teams." }, + { label: "Enterprise", value: "enterprise", disabled: true }, + ], + }), + ); + + const root = dom.querySelector(".wire-next--radio-field") as HTMLElement; + const controls = [...dom.querySelectorAll('input[type="radio"]')] as HTMLInputElement[]; + expect(root.dataset.orientation).toBe("horizontal"); + expect(root.dataset.card).toBe("true"); + expect(root.dataset.list).toBe("true"); + expect(root.dataset.rightAligned).toBe("true"); + expect(controls).toHaveLength(3); + expect(controls[1]?.checked).toBe(true); + expect(controls[2]?.disabled).toBe(true); + expect(dom.querySelectorAll(".wire-next__choice-copy small")).toHaveLength(2); +}); + +test("checkbox renders passed values in group, card, list, alignment, description, and mixed layouts", async () => { + const source = readFileSync(uiComponentPath("Checkbox"), "utf8"); + const group = mountHtml( + await renderComponent(source, { + id: "notifications", + name: "notifications", + label: "Notification preferences", + values: ["account"], + orientation: "horizontal", + card: true, + list: true, + rightAligned: true, + options: [ + { label: "Product", value: "product", description: "Product news." }, + { label: "Account", value: "account", description: "Security alerts." }, + { label: "Partners", value: "partners", disabled: true }, + ], + }), + ); + const controls = [...group.querySelectorAll('input[type="checkbox"]')] as HTMLInputElement[]; + expect(group.querySelector(".wire-next--checkbox-field")?.getAttribute("data-orientation")).toBe( + "horizontal", + ); + expect(controls).toHaveLength(3); + expect(controls[1]?.checked).toBe(true); + expect(controls[2]?.disabled).toBe(true); + expect(group.querySelectorAll(".wire-next__choice-copy small")).toHaveLength(2); + + const mixed = mountHtml( + await renderComponent(source, { id: "mixed", name: "mixed", indeterminate: true }), + ); + expect(mixed.querySelector("input")?.getAttribute("aria-checked")).toBe("mixed"); +}); + +test("range slider exposes value, minimum, maximum, step, bounds, and optional marks", async () => { + const source = readFileSync(uiComponentPath("RangeSlider"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "volume", + name: "volume", + value: 50, + min: 0, + max: 100, + step: 25, + showBounds: true, + showSteps: true, + marks: [ + { value: 0, label: "Minimum" }, + { value: 50, label: "Middle" }, + { value: 100, label: "Maximum" }, + ], + }), + ); + + const control = dom.querySelector('input[type="number"]') as HTMLInputElement; + const slider = dom.querySelector('[role="slider"]') as HTMLElement; + expect(control.min).toBe("0"); + expect(control.max).toBe("100"); + expect(control.step).toBe("25"); + expect(slider.getAttribute("aria-valuenow")).toBe("50"); + expect(dom.querySelector(".wire-next__range-bounds")?.textContent).toContain("Step 25"); + expect(dom.querySelectorAll(".wire-next__slider-marks button")).toHaveLength(3); + expect(slider.getAttribute("tabindex")).toBe("0"); + expect(source).toContain('sourceEvent.key === "ArrowRight"'); + const increase = dom.querySelector('[aria-label="Increase Range"]') as HTMLButtonElement; + increase.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector('[role="slider"]')?.getAttribute("aria-valuenow")).toBe("75"); + dom + .querySelector('[role="slider"]') + ?.dispatchEvent( + new (dom.window as any).KeyboardEvent("keydown", { key: "ArrowRight", bubbles: true }), + ); + expect(dom.querySelector('[role="slider"]')?.getAttribute("aria-valuenow")).toBe("100"); + const middleMark = dom.querySelectorAll( + ".wire-next__slider-marks button", + )[1] as HTMLButtonElement; + middleMark.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector('[role="slider"]')?.getAttribute("aria-valuenow")).toBe("50"); + expect((dom.querySelector('input[type="number"]') as HTMLInputElement).value).toBe("50"); +}); + +test("date picker renders a custom calendar trigger with accessible field state and events", async () => { + const source = readFileSync(uiComponentPath("DatePicker"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "start-date", + name: "startDate", + label: "Start date", + value: "2026-07-28", + min: "2026-01-01", + max: "2026-12-31", + helperText: "Use your local date.", + cornerHint: "Required", + required: true, + }), + ); + const input = dom.querySelector("input") as HTMLInputElement; + expect(input.type).toBe("text"); + expect(input.required).toBe(true); + expect(dom.querySelector("label")?.getAttribute("for")).toBe("start-date"); + expect(dom.querySelector('button[aria-haspopup="dialog"]')).not.toBeNull(); + expect(source).not.toContain('type="{type}"'); + expect(source).toContain("months ="); + expect(dom.querySelector(".wire-next__field-help")?.textContent).toContain("local date"); + const trigger = dom.querySelector('button[aria-haspopup="dialog"]') as HTMLButtonElement; + expect(dom.querySelector(".wire-next--date-picker")?.getAttribute("data-expanded")).toBe("false"); + trigger.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector(".wire-next--date-picker")?.getAttribute("data-expanded")).toBe("true"); + expect(dom.querySelector('button[aria-haspopup="dialog"]')?.getAttribute("aria-expanded")).toBe( + "true", + ); + expect(dom.querySelectorAll(".wire-next__calendar-grid button")).toHaveLength(31); + const fifteenth = dom.querySelectorAll( + ".wire-next__calendar-grid button", + )[14] as HTMLButtonElement; + fifteenth.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(input.value).toBe("2026-07-15"); + expect(dom.querySelector(".wire-next__date-trigger span")?.textContent).toBe("2026-07-15"); +}); + +test("time picker uses a custom reactive panel instead of the browser time control", async () => { + const source = readFileSync(uiComponentPath("TimePicker"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "meeting-time", + name: "meetingTime", + value: "13:30", + format: "12", + minuteStep: 15, + }), + ); + expect(source).not.toContain('type="time"'); + const trigger = dom.querySelector(".wire-next__time-trigger") as HTMLButtonElement; + expect(trigger.textContent).toContain("13:30"); + trigger.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector(".wire-next--time-picker")?.getAttribute("data-expanded")).toBe("true"); + expect(dom.querySelectorAll(".wire-next__time-options").length).toBe(2); + expect(dom.querySelectorAll(".wire-next__time-options button")).toHaveLength(36); + const nine = [...dom.querySelectorAll(".wire-next__time-options button")].find( + (button) => button.textContent?.trim() === "09", + ) as HTMLButtonElement; + nine.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect((dom.querySelector('input[name="meetingTime"]') as HTMLInputElement).value).toBe("09:30"); + expect(dom.querySelector(".wire-next__time-trigger span")?.textContent).toBe("09:30"); +}); + +test("file upload progress reacts to cancel, retry, and complete actions", async () => { + const source = readFileSync(uiComponentPath("FileUploadProgress"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + fileName: "design-system.zip", + fileSize: "20 MB", + uploadedSize: "10 MB", + value: 50, + max: 100, + status: "uploading", + }), + ); + expect(dom.querySelector(".wire-next--file-upload-progress")?.getAttribute("data-status")).toBe( + "uploading", + ); + expect(dom.querySelector(".wire-next__row")?.textContent).toContain("design-system.zip"); + const buttons = dom.querySelectorAll(".wire-next__upload-actions button") as HTMLButtonElement[]; + buttons[0]?.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector(".wire-next--file-upload-progress")?.getAttribute("data-status")).toBe( + "cancelled", + ); +}); + +test("carousel renders accessible slides, pagination, counter, and navigation events", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const html = await renderComponent(source, { + ariaLabel: "Featured stories", + showPagination: true, + showCounter: true, + items: [ + { title: "First story", description: "First description" }, + { title: "Second story", description: "Second description" }, + { title: "Third story", description: "Third description" }, + ], + }); + const dom = mountHtml(html); + const carousel = dom.querySelector(".wire-next--carousel") as HTMLElement; + const scopeRoot = dom.querySelector("[data-wrn-scope]") as HTMLElement; + const encodedScope = scopeRoot.getAttribute("data-wrn-scope") ?? ""; + const hydratedScope = JSON.parse(Buffer.from(encodedScope, "base64").toString("utf8")) as { + items: Array<{ title: string }>; + }; + const events: string[] = []; + for (const name of ["change", "next", "previous"]) { + carousel.addEventListener(name, () => events.push(name)); + } + + expect(carousel.getAttribute("role")).toBe("region"); + expect(carousel.getAttribute("aria-roledescription")).toBe("carousel"); + expect(carousel.getAttribute("aria-label")).toBe("Featured stories"); + expect(hydratedScope.items.map((item) => item.title)).toEqual([ + "First story", + "Second story", + "Third story", + ]); + expect(dom.querySelectorAll('[aria-roledescription="slide"]')).toHaveLength(3); + expect(dom.querySelectorAll(".wire-next__carousel-pagination button")).toHaveLength(3); + expect(dom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("1 / 3"); + + (dom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement).click(); + expect(dom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("2 / 3"); + expect(events).toEqual(["change", "next"]); + + (dom.querySelector('[aria-label="Previous slide"]') as HTMLButtonElement).click(); + expect(events).toEqual(["change", "next", "change", "previous"]); +}); + +test("carousel supports RTL, multiple slides, dragging, snap, and thumbnail layouts", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const items = [{ title: "First" }, { title: "Second" }, { title: "Third" }, { title: "Fourth" }]; + const html = await renderComponent(source, { + items, + slidesPerView: 3, + isRTL: true, + isDraggable: true, + isAutoHeight: true, + thumbnails: "vertical", + }); + const dom = mountHtml(html); + const carousel = dom.querySelector(".wire-next--carousel") as HTMLElement; + const track = dom.querySelector(".wire-next__carousel-track") as HTMLElement; + + expect(carousel.getAttribute("dir")).toBe("rtl"); + expect(carousel.dataset.draggable).toBe("true"); + expect(carousel.dataset.autoHeight).toBe("true"); + expect(carousel.dataset.thumbnails).toBe("vertical"); + expect(track.getAttribute("style")).toContain("--wire-carousel-per-view: 3"); + expect(dom.querySelectorAll(".wire-next__carousel-thumbnails button")).toHaveLength(4); + + const snapHtml = await renderComponent(source, { + items, + isSnap: true, + isDraggable: true, + }); + const snapDom = mountHtml(snapHtml); + const snapRoot = snapDom.querySelector(".wire-next--carousel") as HTMLElement; + expect(snapRoot.dataset.snap).toBe("true"); + expect(snapRoot.dataset.draggable).toBe("false"); + + const css = uiCss(); + expect(css).toContain('.wire-next--carousel[data-rtl="true"]'); + expect(css).toContain('.wire-next--carousel[data-snap="true"]'); + expect(css).toContain('.wire-next--carousel[data-thumbnails="vertical"]'); + expect(css).toContain("user-select: none"); + expect(css).toContain('.wire-next--carousel[data-centered="true"] .wire-next__carousel-track'); +}); + +test("carousel autoplay timers are available in the browser reactive runtime", async () => { + const { getReactiveRuntime } = await import("../../csr/src/index.ts"); + const runtime = getReactiveRuntime(); + expect(runtime).toContain('name === "setInterval"'); + expect(runtime).toContain('name === "clearInterval"'); +}); + +test("carousel snap controls scroll and multiple slides stop at the last full group", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const items = [ + { title: "First" }, + { title: "Second" }, + { title: "Third" }, + { title: "Fourth" }, + { title: "Fifth" }, + { title: "Sixth" }, + ]; + const snapDom = mountHtml( + await renderComponent(source, { + items, + isSnap: true, + showPagination: true, + }), + ); + const viewport = snapDom.querySelector(".wire-next__carousel-viewport") as HTMLElement & { + scrollTo: (options: ScrollToOptions) => void; + }; + let scrollLeft: number | undefined; + viewport.scrollTo = (options: ScrollToOptions | number) => { + scrollLeft = typeof options === "number" ? options : options.left; + }; + ( + snapDom.querySelectorAll(".wire-next__carousel-pagination button")[1] as HTMLButtonElement + ).click(); + expect(scrollLeft).toBeDefined(); + const snapNext = snapDom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement; + for (let index = 0; index < items.length; index++) snapNext.click(); + const paginationButtons = snapDom.querySelectorAll(".wire-next__carousel-pagination button"); + expect(paginationButtons[items.length - 1]?.getAttribute("aria-current")).toBe("true"); + expect(snapNext.disabled).toBe(true); + + const multipleDom = mountHtml( + await renderComponent(source, { + items, + slidesPerView: 3, + showCounter: true, + }), + ); + const next = multipleDom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement; + for (let index = 0; index < 6; index++) next.click(); + expect(multipleDom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("4 / 6"); + expect(next.disabled).toBe(true); +}); + +test("carousel centers the last slide and auto-scrolls thumbnail rails", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const items = [{ title: "First" }, { title: "Second" }, { title: "Third" }, { title: "Fourth" }]; + const centeredDom = mountHtml( + await renderComponent(source, { + items, + isCentered: true, + showCounter: true, + }), + ); + const centeredNext = centeredDom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement; + for (let index = 0; index < items.length; index++) centeredNext.click(); + expect(centeredDom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("4 / 4"); + expect(centeredNext.disabled).toBe(true); + + for (const thumbnails of ["horizontal", "vertical"]) { + const dom = mountHtml(await renderComponent(source, { items, thumbnails })); + const buttons = dom.querySelectorAll( + ".wire-next__carousel-thumbnails button", + ) as HTMLButtonElement[]; + let scrolled = false; + const rail = buttons[1]?.parentElement as HTMLElement & { + scrollTo: (options: ScrollToOptions) => void; + }; + rail.scrollTo = () => { + scrolled = true; + }; + (dom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement).click(); + expect(scrolled).toBe(true); + } +}); + +test("carousel autoplay wraps to the first slide", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const html = await renderComponent(source, { + isAutoPlay: true, + autoplayInterval: 1000, + activeIndex: 2, + showCounter: true, + items: [{ title: "First" }, { title: "Second" }, { title: "Third" }], + }); + const dom = mountHtml(html); + await Bun.sleep(1100); + expect(dom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("1 / 3"); + dom + .querySelector(".wire-next--carousel") + ?.dispatchEvent(new (dom.window as any).Event("mouseenter", { bubbles: true })); +}); + +test("input number increments, decrements, applies steps, and respects limits", async () => { + const source = readFileSync(uiComponentPath("InputNumber"), "utf8"); + const html = await renderComponent(source, { + name: "quantity", + value: 1, + min: 0, + max: 5, + step: 2, + }); + const dom = mountHtml(html); + const input = () => dom.querySelector('input[name="quantity"]') as HTMLInputElement; + const decrement = () => dom.querySelector('[aria-label="Decrease value"]') as HTMLButtonElement; + const increment = () => dom.querySelector('[aria-label="Increase value"]') as HTMLButtonElement; + + expect(input().value).toBe("1"); + + increment().click(); + expect(input().value).toBe("3"); + + increment().click(); + expect(input().value).toBe("5"); + expect(increment().disabled).toBe(true); + + decrement().click(); + expect(input().value).toBe("3"); + + decrement().click(); + decrement().click(); + expect(input().value).toBe("0"); + expect(decrement().disabled).toBe(true); +}); + +test("advanced select opens, filters, and selects without reactive handler errors", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const html = await renderComponent(source, { + name: "team", + options: [ + { value: "design", label: "Design" }, + { value: "engineering", label: "Engineering" }, + { value: "growth", label: "Growth" }, + ], + }); + const dom = mountHtml(html); + const trigger = dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement; + expect(trigger).not.toBeNull(); + trigger.click(); + expect( + dom.querySelector(".wire-next--advanced-select")?.classList.contains("wire-next--open"), + ).toBe(true); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("true"); + expect(dom.querySelector('[role="listbox"]')).not.toBeNull(); + const search = dom.querySelector(".wire-next__select-search input") as HTMLInputElement; + search.value = "engine"; + search.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + const options = dom.querySelectorAll(".wire-next__select-option") as HTMLButtonElement[]; + expect(options.filter((option) => option.style.display !== "none")).toHaveLength(1); + options.find((option) => option.style.display !== "none")?.click(); + expect(dom.querySelector(".wire-next__select-value > span")?.textContent).toBe("Engineering"); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("false"); + (dom.querySelector(".wire-next__clear-select") as HTMLButtonElement).click(); + expect(dom.querySelector(".wire-next__select-value > span")?.textContent).toBe( + "Select an option", + ); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe(""); +}); + +test("advanced select clears, restores its placeholder, and keeps multiple counters accurate", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const html = await renderComponent(source, { + name: "team", + multiple: true, + values: ["design", "engineering"], + showCounter: true, + maxSelections: 3, + placeholder: "Choose teams", + options: [ + { value: "design", label: "Design" }, + { value: "engineering", label: "Engineering" }, + { value: "growth", label: "Growth" }, + ], + }); + const dom = mountHtml(html); + const trigger = dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement; + const counter = dom.querySelector(".wire-next__row small"); + expect(counter?.textContent).toBe("2 / 3 selected"); + + trigger.click(); + const buttons = dom.querySelectorAll(".wire-next__select-option") as HTMLButtonElement[]; + const scope = dom.querySelector("[data-wrn-select]") as HTMLElement & { + __wrnexusScopeApi?: { + get(name: string): unknown; + call(name: string, value?: unknown): unknown; + }; + }; + expect(scope.__wrnexusScopeApi?.get("maxSelections")).toBe(3); + expect(scope.__wrnexusScopeApi?.call("selectedCount")).toBe(2); + expect(scope.__wrnexusScopeApi?.call("canSelect", { value: "growth", label: "Growth" })).toBe( + true, + ); + expect(buttons.find((button) => button.textContent?.includes("Growth"))?.disabled).toBe(false); + buttons.find((button) => button.textContent?.includes("Engineering"))?.click(); + expect(counter?.textContent).toBe("1 / 3 selected"); + buttons.find((button) => button.textContent?.includes("Design"))?.click(); + expect(counter?.textContent).toBe("0 / 3 selected"); + expect( + dom.querySelector(".wire-next__placeholder")?.parentElement?.getAttribute("data-show"), + ).toBe("true"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe(""); +}); + +test("advanced select closes when a pointer event occurs outside it", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const html = await renderComponent(source, { + name: "team", + options: [{ value: "design", label: "Design" }], + }); + const dom = mountHtml(html); + (dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement).click(); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("true"); + dom.document.body.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("pointerdown", { bubbles: true }), + ); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("false"); +}); + +test("advanced select fetches remote options and appends infinite pages", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const originalFetch = globalThis.fetch; + const requests: string[] = []; + globalThis.fetch = (async (input: string | URL | Request) => { + const url = String(input); + requests.push(url); + const parsedUrl = new URL(url); + const page = parsedUrl.searchParams.get("page"); + const query = parsedUrl.searchParams.get("q"); + return Response.json( + page === "1" + ? { + items: query + ? [{ value: "engineering", label: "Engineering" }] + : [{ value: "design", label: "Design" }], + hasMore: true, + } + : { items: [{ value: "support", label: "Support" }], hasMore: false }, + ); + }) as unknown as typeof fetch; + + try { + const html = await renderComponent(source, { + name: "team", + options: [], + remote: true, + remoteUrl: "https://example.test/api/teams", + infinite: true, + hasMore: true, + remoteDebounce: 0, + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-select]") as HTMLElement & { + __wrnexusSelectController?: { attempts: number }; + __wrnexusScopeApi?: { get(name: string): unknown }; + }; + expect(root.getAttribute("data-remote")).toBe("true"); + expect(root.getAttribute("data-remote-url")).toBe("https://example.test/api/teams"); + expect(root.getAttribute("data-remote-auto-load")).toBe("true"); + expect(root.__wrnexusSelectController).toBeDefined(); + expect(root.__wrnexusScopeApi).toBeDefined(); + expect(root.__wrnexusScopeApi?.get("minSearchLength")).toBe(0); + expect(root.__wrnexusSelectController?.attempts).toBe(1); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(requests).toHaveLength(1); + expect( + dom.querySelectorAll(".wire-next__select-option").map((node) => node.textContent), + ).toEqual(["Design"]); + (dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement).click(); + (dom.querySelector(".wire-next__select-option") as HTMLButtonElement).click(); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe("design"); + expect(dom.querySelector(".wire-next__select-value > span")?.textContent).toBe("Design"); + + const search = dom.querySelector(".wire-next__select-search input") as HTMLInputElement; + search.value = "engine"; + search.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(requests.at(-1)).toContain("q=engine"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe("design"); + expect(dom.querySelector(".wire-next__select-value > span")?.textContent).toBe("Design"); + + (dom.querySelector("[data-wrn-select-load-more]") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect( + dom.querySelectorAll(".wire-next__select-option").map((node) => node.textContent), + ).toEqual(["Engineering", "Support"]); + expect(requests).toHaveLength(3); + expect(requests[2]).toContain("page=2"); + } finally { + globalThis.fetch = originalFetch; + } +}); + +test("combobox filters editable input, selects suggestions, exposes methods, and clears", async () => { + const source = readFileSync(uiComponentPath("ComboBox"), "utf8"); + const html = await renderComponent(source, { + name: "team", + placeholder: "Search teams", + options: [ + { value: "design", label: "Design", description: "Product design" }, + { value: "engineering", label: "Engineering", description: "Platform engineering" }, + { value: "growth", label: "Growth", description: "Customer growth" }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-combobox]") as HTMLElement & { + wrnexusCombobox?: { + open(): void; + close(): void; + clear(): void; + setValue(value: string): void; + }; + }; + const input = dom.querySelector(".wire-next__combobox-input") as HTMLInputElement; + const hidden = dom.querySelector('input[type="hidden"]') as HTMLInputElement; + + expect(root.wrnexusCombobox).toBeDefined(); + input.focus(); + input.value = "engi"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect( + dom + .querySelectorAll(".wire-next__select-option") + .filter((option) => (option as HTMLElement).style.display !== "none") + .map((option) => option.textContent?.trim()), + ).toEqual(["EngineeringPlatform engineering"]); + + input.value = "No matching team"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("false"); + expect(input.value).toBe("No matching team"); + + input.value = "engi"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + input.dispatchEvent( + new (dom.window as { KeyboardEvent: typeof KeyboardEvent }).KeyboardEvent("keydown", { + key: "Enter", + bubbles: true, + }), + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(input.value).toBe("Engineering"); + expect(hidden.value).toBe("engineering"); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("false"); + + root.wrnexusCombobox?.clear(); + expect(input.value).toBe(""); + expect(hidden.value).toBe(""); + root.wrnexusCombobox?.setValue("growth"); + expect(input.value).toBe("Growth"); + expect(hidden.value).toBe("growth"); +}); + +test("combobox auto-loads remote suggestions and retains its selected value while searching", async () => { + const source = readFileSync(uiComponentPath("ComboBox"), "utf8"); + const originalFetch = globalThis.fetch; + const requests: string[] = []; + globalThis.fetch = (async (input: string | URL | Request) => { + const url = new URL(String(input)); + requests.push(url.toString()); + const query = url.searchParams.get("q"); + return Response.json({ + items: query + ? [{ value: "engineering", label: "Engineering" }] + : [{ value: "design", label: "Design" }], + hasMore: false, + }); + }) as typeof fetch; + + try { + const html = await renderComponent(source, { + name: "remote-team", + remote: true, + remoteUrl: "https://example.test/api/teams", + remoteDebounce: 0, + }); + const dom = mountHtml(html); + const input = dom.querySelector(".wire-next__combobox-input") as HTMLInputElement; + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(requests).toHaveLength(1); + + input.focus(); + (dom.querySelector(".wire-next__select-option") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(input.value).toBe("Design"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe("design"); + + input.value = "engine"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(requests.at(-1)).toContain("q=engine"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe(""); + (dom.querySelector(".wire-next__select-option") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(input.value).toBe("Engineering"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe( + "engineering", + ); + } finally { + globalThis.fetch = originalFetch; + } +}); + +test("combobox emits search, select, change, clear, open, and close events", async () => { + const source = readFileSync(uiComponentPath("ComboBox"), "utf8"); + const html = await renderComponent(source, { + name: "events-team", + options: [ + { value: "design", label: "Design" }, + { value: "engineering", label: "Engineering" }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-combobox]") as HTMLElement; + const input = dom.querySelector(".wire-next__combobox-input") as HTMLInputElement; + const received: Array<{ name: string; detail: Record }> = []; + for (const name of ["search", "select", "change", "clear", "open", "close"]) { + root.addEventListener(`wrnexus:${name}`, ((event: CustomEvent) => { + received.push({ name, detail: event.detail }); + }) as EventListener); + } + + input.focus(); + await new Promise((resolve) => setTimeout(resolve, 0)); + input.value = "engi"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + input.dispatchEvent( + new (dom.window as { KeyboardEvent: typeof KeyboardEvent }).KeyboardEvent("keydown", { + key: "Enter", + bubbles: true, + }), + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + (dom.querySelector(".wire-next__clear-select") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + + expect(received.map((event) => event.name)).toEqual( + expect.arrayContaining(["search", "select", "change", "clear", "open", "close"]), + ); + expect(received.find((event) => event.name === "search")?.detail).toEqual( + expect.objectContaining({ component: "ComboBox", query: "engi" }), + ); + expect(received.find((event) => event.name === "select")?.detail).toEqual( + expect.objectContaining({ value: "engineering" }), + ); +}); + +test("advanced select emits selection events and remote load and error events", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const originalFetch = globalThis.fetch; + const originalConsoleError = console.error; + let rejectRequest = false; + globalThis.fetch = (async () => { + if (rejectRequest) throw new Error("Remote unavailable"); + return Response.json({ + items: [{ value: "design", label: "Design" }], + hasMore: false, + }); + }) as unknown as typeof fetch; + console.error = () => {}; + + try { + const html = await renderComponent(source, { + name: "advanced-events", + options: [], + remote: true, + remoteUrl: "https://example.test/api/teams", + remoteAutoLoad: true, + remoteDebounce: 0, + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-select]") as HTMLElement & { + __wrnexusSelectController?: { load(append: boolean, allowEmptyQuery?: boolean): void }; + }; + const received: Array<{ name: string; detail: Record }> = []; + for (const name of ["load", "error", "select", "change", "clear"]) { + root.addEventListener(`wrnexus:${name}`, ((event: CustomEvent) => { + received.push({ name, detail: event.detail }); + }) as EventListener); + } + + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + (dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement).click(); + (dom.querySelector(".wire-next__select-option") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + (dom.querySelector(".wire-next__clear-select") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + + rejectRequest = true; + root.__wrnexusSelectController?.load(false, true); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + + expect(received.map((event) => event.name)).toEqual( + expect.arrayContaining(["load", "select", "change", "clear", "error"]), + ); + expect(received.find((event) => event.name === "load")?.detail).toEqual( + expect.objectContaining({ + component: "AdvancedSelect", + page: 1, + hasMore: false, + }), + ); + expect(received.find((event) => event.name === "error")?.detail).toEqual( + expect.objectContaining({ + component: "AdvancedSelect", + message: "Remote unavailable", + }), + ); + } finally { + globalThis.fetch = originalFetch; + console.error = originalConsoleError; + } +}); + +test("pin input accepts matching characters, advances focus, navigates backward, and completes", async () => { + const source = readFileSync(uiComponentPath("PinInput"), "utf8"); + const html = await renderComponent(source, { + name: "verificationCode", + length: 4, + pattern: "[0-9]", + value: "", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-pin-input]") as HTMLElement & { + wrnexusPinInput?: { + focus(index?: number): void; + clear(): void; + setValue(value: string): void; + getValue(): string; + }; + }; + const cells = dom.querySelectorAll("[data-pin-cell]") as HTMLInputElement[]; + const hidden = dom.querySelector("[data-pin-value]") as HTMLInputElement; + const events: string[] = []; + const publicEvents: string[] = []; + for (const name of ["input", "change", "complete", "clear"]) { + root.addEventListener(`wrnexus:${name}`, () => events.push(name)); + root.addEventListener(name, () => publicEvents.push(name)); + } + + expect(cells).toHaveLength(4); + expect(root.wrnexusPinInput).toBeDefined(); + cells[0].focus(); + cells[0].value = "x"; + cells[0].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect(cells[0].value).toBe(""); + expect(hidden.value).toBe(""); + + for (let index = 0; index < 4; index += 1) { + cells[index].value = String(index + 1); + cells[index].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + } + expect(hidden.value).toBe("1234"); + expect(root.getAttribute("data-complete")).toBe("true"); + expect(events).toContain("complete"); + expect(publicEvents).toContain("complete"); + + cells[3].value = ""; + cells[3].dispatchEvent( + new (dom.window as { KeyboardEvent: typeof KeyboardEvent }).KeyboardEvent("keydown", { + key: "Backspace", + bubbles: true, + }), + ); + expect(cells[2].value).toBe(""); + expect(hidden.value).toBe("12"); + + root.wrnexusPinInput?.setValue("9876"); + expect(root.wrnexusPinInput?.getValue()).toBe("9876"); + root.wrnexusPinInput?.clear(); + expect(hidden.value).toBe(""); + expect(events).toContain("clear"); +}); + +test("pin input renders four separate cells when length is omitted", async () => { + const source = readFileSync(uiComponentPath("PinInput"), "utf8"); + const html = await renderComponent(source, { + name: "defaultPin", + }); + const dom = mountHtml(html); + + expect(dom.querySelectorAll("[data-pin-cell]")).toHaveLength(4); +}); + +test("pin input distributes filtered clipboard content and emits paste details", async () => { + const source = readFileSync(uiComponentPath("PinInput"), "utf8"); + const html = await renderComponent(source, { + name: "emailCode", + length: 6, + pattern: "[A-Z0-9]", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-pin-input]") as HTMLElement; + const firstCell = dom.querySelector("[data-pin-cell]") as HTMLInputElement; + let pasteDetail: Record | undefined; + root.addEventListener("wrnexus:paste", ((event: CustomEvent) => { + pasteDetail = event.detail; + }) as EventListener); + + const pasteEvent = new (dom.window as { Event: typeof Event }).Event("paste", { + bubbles: true, + cancelable: true, + }); + Object.defineProperty(pasteEvent, "clipboardData", { + value: { getData: () => "A-1b2 C3" }, + }); + firstCell.dispatchEvent(pasteEvent); + + expect((dom.querySelector("[data-pin-value]") as HTMLInputElement).value).toBe("A1B2C3"); + expect(pasteDetail).toEqual( + expect.objectContaining({ + component: "PinInput", + pasted: "A1B2C3", + value: "A1B2C3", + }), + ); +}); + +test("pin input accepts lowercase alphanumeric entry and normalizes it to the configured pattern", async () => { + const source = readFileSync(uiComponentPath("PinInput"), "utf8"); + const html = await renderComponent(source, { + name: "securityCode", + length: 4, + pattern: "[A-Z0-9]", + inputMode: "text", + }); + const dom = mountHtml(html); + const cells = dom.querySelectorAll("[data-pin-cell]") as HTMLInputElement[]; + + cells[0].value = "a"; + cells[0].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + + expect(cells[0].value).toBe("A"); + expect((dom.querySelector("[data-pin-value]") as HTMLInputElement).value).toBe("A"); +}); + +test("strong password scores input, supports custom special characters, and opens its popover", async () => { + const source = readFileSync(uiComponentPath("StrongPassword"), "utf8"); + const html = await renderComponent(source, { + name: "newPassword", + presentation: "popover", + specialCharactersSet: "@#", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-strong-password]") as HTMLElement; + const input = dom.querySelector('input[name="newPassword"]') as HTMLInputElement; + const strengthEvents: Array<{ level: string; percent: number }> = []; + root.addEventListener("strength", (event) => { + strengthEvents.push( + (event as unknown as CustomEvent<{ level: string; percent: number }>).detail, + ); + }); + + expect(input.minLength).toBe(8); + expect(root.dataset.strength).toBe("empty"); + + input.value = "Secure#9"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect((dom.querySelector("[data-wrn-strong-password]") as HTMLElement).dataset.strength).toBe( + "strong", + ); + expect((dom.querySelector("[data-wrn-strong-password]") as HTMLElement).dataset.score).toBe("5"); + expect(strengthEvents.at(-1)).toMatchObject({ level: "strong", percent: 100 }); + + const updatedInput = dom.querySelector('input[name="newPassword"]') as HTMLInputElement; + updatedInput.value = "Secure!9"; + updatedInput.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect((dom.querySelector("[data-wrn-strong-password]") as HTMLElement).dataset.strength).toBe( + "good", + ); + expect(strengthEvents.at(-1)?.percent).toBe(80); + + const currentInput = dom.querySelector('input[name="newPassword"]') as HTMLInputElement; + currentInput.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("focus", { bubbles: true }), + ); + expect( + (dom.querySelector(".wire-next__strong-password-popover") as HTMLElement).dataset.open, + ).toBe("true"); +}); + +test("strong password completed requirements use a proper checkmark indicator", () => { + const css = uiCss(); + + expect(css).toContain( + '.wire-next__strong-password-requirements li[data-met="true"] > span::after', + ); + expect(css).toContain("transform: rotate(45deg)"); + expect(css).toContain("border-width: 0 0.1rem 0.1rem 0"); + expect(css).not.toContain( + "linear-gradient(135deg, transparent 42%, var(--wire-color-surface) 42% 52%", + ); +}); + +test("toggle count switches pricing values and emits accessible change details", async () => { + const source = readFileSync(uiComponentPath("ToggleCount"), "utf8"); + const html = await renderComponent(source, { + name: "billing", + value: "monthly", + firstValue: "monthly", + firstLabel: "Monthly", + secondValue: "annual", + secondLabel: "Annual", + animate: false, + items: [ + { label: "Startup", monthly: 19, annual: 190 }, + { label: "Team", monthly: 89, annual: 890 }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-toggle-count]") as HTMLElement; + let detail: Record | undefined; + root.addEventListener("toggle", (event) => { + detail = (event as unknown as CustomEvent>).detail; + }); + + expect(root.dataset.value).toBe("monthly"); + expect( + dom + .querySelectorAll(".wire-next__toggle-count-items strong > span") + .map((node) => node.textContent), + ).toEqual(["19", "89"]); + + (dom.querySelector('button[aria-pressed="false"]') as HTMLButtonElement).click(); + + const updatedRoot = dom.querySelector("[data-wrn-toggle-count]") as HTMLElement; + expect(updatedRoot.dataset.value).toBe("annual"); + expect( + dom + .querySelectorAll(".wire-next__toggle-count-items strong > span") + .map((node) => node.textContent), + ).toEqual(["190", "890"]); + expect((dom.querySelector('input[name="billing"]') as HTMLInputElement).value).toBe("annual"); + expect(dom.querySelector('button[aria-pressed="true"]')?.textContent).toBe("Annual"); + expect(detail).toMatchObject({ + component: "ToggleCount", + name: "billing", + value: "annual", + previousValue: "monthly", + }); +}); + +test("toggle count animates every price upward and downward", async () => { + const source = readFileSync(uiComponentPath("ToggleCount"), "utf8"); + const html = await renderComponent(source, { + value: "monthly", + animationDuration: 40, + animationSteps: 4, + items: [ + { label: "Startup", monthly: 2, annual: 10 }, + { label: "Team", monthly: 4, annual: 20 }, + ], + }); + const dom = mountHtml(html); + const values = () => + dom.querySelectorAll("[data-toggle-count-value]").map((node) => Number(node.textContent)); + const button = (label: string) => + dom + .querySelectorAll(".wire-next__toggle-count-segmented button") + .find((node) => node.textContent === label) as HTMLButtonElement; + + button("Annual").click(); + expect(values()).toEqual([2, 4]); + await new Promise((resolve) => setTimeout(resolve, 15)); + expect(values().every((value) => Number.isInteger(value))).toBe(true); + await new Promise((resolve) => setTimeout(resolve, 80)); + expect(values()).toEqual([10, 20]); + + button("Monthly").click(); + expect(values()).toEqual([10, 20]); + await new Promise((resolve) => setTimeout(resolve, 15)); + expect(values().every((value) => Number.isInteger(value))).toBe(true); + await new Promise((resolve) => setTimeout(resolve, 80)); + expect(values()).toEqual([2, 4]); +}); + +test("toggle count switch exposes switch semantics and respects disabled state", async () => { + const source = readFileSync(uiComponentPath("ToggleCount"), "utf8"); + const html = await renderComponent(source, { + variant: "switch", + value: "monthly", + disabled: true, + items: [{ label: "Startup", monthly: 19, annual: 190 }], + }); + const dom = mountHtml(html); + const control = dom.querySelector('[role="switch"]') as HTMLButtonElement; + + expect(control.getAttribute("aria-checked")).toBe("false"); + expect(control.disabled).toBe(true); + control.click(); + expect((dom.querySelector("[data-wrn-toggle-count]") as HTMLElement).dataset.value).toBe( + "monthly", + ); +}); + +test("toggle password reveals and conceals its value with accessible declared events", async () => { + const source = readFileSync(uiComponentPath("TogglePassword"), "utf8"); + const html = await renderComponent(source, { + name: "accountPassword", + value: "correct-horse", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-toggle-password]") as HTMLElement; + const input = dom.querySelector('input[name="accountPassword"]') as HTMLInputElement; + const toggle = dom.querySelector(".wire-next__password-toggle") as HTMLButtonElement; + const showIcon = dom.querySelector(".wire-next__password-icon--show") as HTMLElement; + const visibility: boolean[] = []; + root.addEventListener("toggle", (event) => { + visibility.push((event as unknown as CustomEvent).detail.visible); + }); + + expect(input.type).toBe("password"); + expect(input.pattern).toBe("(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}"); + expect(showIcon).not.toBeNull(); + expect(toggle.getAttribute("aria-pressed")).toBe("false"); + toggle.click(); + expect(input.type).toBe("text"); + expect(input.value).toBe("correct-horse"); + expect(toggle.getAttribute("aria-pressed")).toBe("true"); + expect(visibility).toEqual([true]); + toggle.click(); + expect(input.type).toBe("password"); + expect(visibility).toEqual([true, false]); +}); + +test("toggle password supports checkbox control and synchronized password fields", async () => { + const source = readFileSync(uiComponentPath("TogglePassword"), "utf8"); + const synchronizedHtml = await renderComponent(source, { + name: "credentials", + fields: [ + { + label: "New password", + name: "newPassword", + placeholder: "Enter new password", + autocomplete: "new-password", + }, + { + label: "Current password", + name: "currentPassword", + value: "existing-secret", + autocomplete: "current-password", + pattern: ".{12,}", + }, + ], + }); + const synchronizedDom = mountHtml(synchronizedHtml); + const synchronizedInputs = synchronizedDom.querySelectorAll( + ".wire-next__password-control > input", + ) as HTMLInputElement[]; + const synchronizedToggle = synchronizedDom.querySelector( + ".wire-next__password-toggle", + ) as HTMLButtonElement; + + expect(synchronizedInputs).toHaveLength(2); + expect(synchronizedInputs[0].pattern).toBe( + "(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}", + ); + expect(synchronizedInputs[1].pattern).toBe(".{12,}"); + expect(synchronizedInputs.map((input) => input.type)).toEqual(["password", "password"]); + synchronizedToggle.click(); + expect(synchronizedInputs.map((input) => input.type)).toEqual(["text", "text"]); + + const checkboxHtml = await renderComponent(source, { + name: "checkboxPassword", + toggleMode: "checkbox", + }); + const checkboxDom = mountHtml(checkboxHtml); + const checkbox = checkboxDom.querySelector( + ".wire-next__password-checkbox input", + ) as HTMLInputElement; + const checkboxPassword = checkboxDom.querySelector( + ".wire-next__password-control > input", + ) as HTMLInputElement; + checkbox.checked = true; + checkbox.dispatchEvent( + new (checkboxDom.window as { Event: typeof Event }).Event("change", { bubbles: true }), + ); + + expect(checkboxPassword.type).toBe("text"); +}); diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Accordion.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Accordion.wrn new file mode 100644 index 00000000..8e75cc66 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Accordion.wrn @@ -0,0 +1,203 @@ +component Accordion { + props { + size = "default" + color = "primary" + variant = "default" + class = "" + + id = "accordion" + items = [] + defaultOpen = [] + multiple = false + alwaysOpen = false + disabled = false + + indicator = "plus" + indicatorPosition = "start" + showIndicator = true + bordered = false + separated = false + flush = false + contentItalic = false + + @event change = function + @event open = function + @event close = function + } + + state openValues = defaultOpen + + functions { + function itemValue(item, index) { + return item.value !== undefined && item.value !== "" + ? String(item.value) + : String(index) + } + + function nestedValue(parent, parentIndex, item, index) { + return itemValue(parent, parentIndex) + "." + itemValue(item, index) + } + + function isOpen(value) { + return openValues.includes(value) + } + + function allowsMultiple() { + return multiple || alwaysOpen + } + + function dispatchAccordionEvent(sourceEvent, eventName, value, item, root, customEvent) { + root = sourceEvent.currentTarget.closest("[data-wrn-accordion]") + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent(eventName, true, false, { + component: "Accordion", + value: value, + item: item, + open: isOpen(value), + openValues: openValues + }) + root.dispatchEvent(customEvent) + } + + function toggleItem(sourceEvent, value, item, wasOpen) { + if (disabled || item.disabled) { + return + } + + wasOpen = isOpen(value) + + if (wasOpen) { + openValues = openValues.filter((entry) => entry !== value) + } else if (allowsMultiple()) { + openValues = openValues.concat([value]) + } else { + openValues = [value] + } + + dispatchAccordionEvent( + sourceEvent, + wasOpen ? "close" : "open", + value, + item + ) + dispatchAccordionEvent(sourceEvent, "change", value, item) + } + + } + + view { +
+ {#each items as item, index} +
+

+ +

+ +
+
+
+ {#if item.content}

{item.content}

{/if} + + {#if item.children && item.children.length > 0} +
+ {#each item.children as child, childIndex} +
+

+ +

+
+
+
+

{child.content}

+
+
+
+
+ {/each} +
+ {/if} +
+
+
+
+ {/each} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AdvancedDatePicker.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AdvancedDatePicker.wrn new file mode 100644 index 00000000..e9664362 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AdvancedDatePicker.wrn @@ -0,0 +1,24 @@ +component AdvancedDatePicker { + props { + @event input = function + @event change = function + @event open = function + @event close = function + @event clear = function + size = "default" + color = "primary" + title = "Advanced Date Picker" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AdvancedRangeSlider.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AdvancedRangeSlider.wrn new file mode 100644 index 00000000..51090087 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AdvancedRangeSlider.wrn @@ -0,0 +1,23 @@ +component AdvancedRangeSlider { + props { + @event input = function + @event change = function + @event start = function + @event end = function + size = "default" + color = "primary" + title = "Advanced Range Slider" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AdvancedSelect.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AdvancedSelect.wrn new file mode 100644 index 00000000..6bd6fe16 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AdvancedSelect.wrn @@ -0,0 +1,456 @@ +component AdvancedSelect { + props { + size = "default" + color = "primary" + label = "Advanced Select" + name = "" + value = "" + values = [] + options = [] + groups = [] + placeholder = "Select an option" + placeholderIcon = "" + searchPlaceholder = "Search options…" + multiple = false + searchable = true + defaultOpen = false + clearable = true + allowEmpty = true + tags = false + disabled = false + required = false + invalid = false + validationMessage = "" + helpText = "" + loading = false + loadingLabel = "Loading options…" + emptyLabel = "No options found" + selectedOptionsLabel = "Selected options" + clearLabel = "Clear selection" + createLabel = "Create" + loadMoreLabel = "Load more" + searchMode = "contains" + searchFields = "label,description" + minSearchLength = 0 + searchResultLimit = 0 + maxSelections = 0 + showCounter = false + counterTemplate = "{selected} selected" + optionTemplate = "default" + selectedTemplate = "default" + closeOnSelect = true + scrollToSelected = true + fixed = false + placement = "bottom" + remote = false + remoteUrl = "" + remoteQueryParam = "q" + remoteDebounce = 250 + remoteAutoLoad = true + infinite = false + hasMore = false + page = 1 + class = "" + @event search = function + @event select = function + @event change = function + @event clear = function + @event open = function + @event close = function + @event load = function + @event error = function + } + + state open = defaultOpen + state query = "" + state activeIndex = -1 + state selectedValue = value + state selectedValues = values + + functions { + function allOptions() { + return [...groups.flatMap((group) => group.options || []), ...options] + } + + function searchableText(option) { + return ((option.label || "") + " " + (option.description || "")).toLowerCase() + } + + function matches(option) { + if (!query || query.length < Number(minSearchLength || 0)) { + return true + } + if (searchMode === "startsWith") { + return searchableText(option).startsWith(query.toLowerCase()) + } + if (searchMode === "exact") { + return searchableText(option) === query.toLowerCase() + } + return searchableText(option).includes(query.toLowerCase()) + } + + function matchingOptions(list) { + return list.filter((option) => matches(option)) + } + + function visibleOptions(list) { + if (searchResultLimit > 0) { + return matchingOptions(list).slice(0, Number(searchResultLimit)) + } + return matchingOptions(list) + } + + function flatVisibleOptions() { + return visibleOptions(allOptions()) + } + + function isSelected(option) { + return ( + multiple + ? selectedValues.includes(option.value) + : selectedValue === option.value + ) + } + + function selectedOptions() { + return allOptions().filter((option) => isSelected(option)) + } + + function selectedCount() { + return multiple ? selectedValues.length : selectedValue ? 1 : 0 + } + + function counterText() { + return ( + maxSelections + ? selectedCount() + " / " + maxSelections + " selected" + : selectedCount() + " selected" + ) + } + + function selectedText() { + return ( + multiple + ? selectedValues.join(", ") + : selectedOptions().length + ? selectedOptions()[0].label + : "" + ) + } + + function triggerText() { + return selectedCount() ? selectedText() : placeholder + } + + function canSelect(option) { + if (option.disabled) { + return false + } + if (!multiple || isSelected(option)) { + return true + } + if (maxSelections <= 0) { + return true + } + return selectedCount() < maxSelections + } + + function chooseSingle(option) { + if (!canSelect(option)) { + return + } + selectedValue = option.value + query = "" + if (closeOnSelect) { + open = false + } + } + + function chooseMultiple(option) { + if (!canSelect(option)) { + return + } + if (isSelected(option)) { + selectedValues = selectedValues.filter((item) => item !== option.value) + } else { + selectedValues = selectedValues.concat([option.value]) + } + query = "" + } + + function chooseOption(option) { + if (multiple) { + chooseMultiple(option) + return + } + chooseSingle(option) + } + + function clearSelection(event) { + event.stopPropagation() + selectedValue = "" + selectedValues = [] + query = "" + open = false + } + + function toggle() { + if (disabled) { + return; + }; + open = !open; + activeIndex = open && flatVisibleOptions().length ? 0 : -1; + } + + function moveActive(direction) { + if (!flatVisibleOptions().length) { + return + } + activeIndex = (activeIndex + direction + flatVisibleOptions().length) % flatVisibleOptions().length + } + + function handleKeydown(event) { + if (disabled) { + return + } + if (event.key === "ArrowDown") { + event.preventDefault() + if (!open) { + open = true + } + moveActive(1) + } else if (event.key === "ArrowUp") { + event.preventDefault() + if (!open) { + open = true + } + moveActive(-1) + } else if (event.key === "Enter" || event.key === " ") { + event.preventDefault() + if (!open) { + open = true + } else if (activeIndex >= 0) { + chooseOption(flatVisibleOptions()[activeIndex]) + } + } else if (event.key === "Escape") { + open = false + } else if (event.key === "Home" && open) { + event.preventDefault() + activeIndex = 0 + } else if (event.key === "End" && open) { + event.preventDefault() + activeIndex = flatVisibleOptions().length - 1 + } + } + + function optionIndex(option) { + return flatVisibleOptions().findIndex((item) => item.value === option.value) + } + } + + view { +
+
+ + {counterText()} +
+ +
+ + + +
+ +
+ {#if searchable} + + {/if} + +
Enter at least {minSearchLength} characters.
+
+ + {loadingLabel} +
+
+ {#each groups as group} + {#if visibleOptions(group.options || []).length} +
+
{group.label}
+ {#each group.options || [] as option} + + {/each} +
+ {/if} + {/each} + + {#each options as option} + + {/each} + + {#if !loading && !flatVisibleOptions().length} +
{emptyLabel}
+ {/if} +
+ + {#if tags && query && !allOptions().some((option) => option.label.toLowerCase() === query.toLowerCase())} + + {/if} + +
+ + + + {#if helpText && !validationMessage}{helpText}{/if} + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AnnouncementBar.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AnnouncementBar.wrn new file mode 100644 index 00000000..3e7341f8 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AnnouncementBar.wrn @@ -0,0 +1,131 @@ +component AnnouncementBar { + props { + badge = "" + badgeIcon = "" + message = "Announcement" + description = "" + icon = "icon-[lucide--megaphone]" + actionLabel = "" + actionHref = "" + actionIcon = "" + dismissible = false + dismissLabel = "Dismiss announcement" + sticky = false + compact = false + size = "default" + color = "primary" + variant = "soft" + role = "status" + live = "polite" + class = "" + } + + state dismissed = false + + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AuthForm.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AuthForm.wrn new file mode 100644 index 00000000..489e0fb4 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AuthForm.wrn @@ -0,0 +1,84 @@ +component AuthForm { + props { + @event submit = function + @event change = function + @event input = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + mode = "sign-in" + action = "/api/auth/login" + method = "post" + title = "Sign in" + description = "" + returnTo = "" + schema = "" + showRemember = true + showName = true + submitLabel = "Continue" + class = "" + } + + functions { + function schemaName() { + if (schema) return schema + if (mode === "sign-in") return "auth-login" + if (mode === "register") return "auth-register" + if (mode === "recover") return "auth-password-request" + if (mode === "reset") return "auth-password-reset" + if (mode === "mfa") return "auth-mfa" + return "auth-empty" + } + + function submitForm(event) { + $emit("submit", { event: event, mode: mode, action: action }) + } + function fieldEvent(type, event) { + const detail = event.detail || {} + $emit(type, { event: event, name: detail.name || "", value: detail.value || "" }) + } + } + + view { +
+
+ +

{title}

{#if description}

{description}

{/if}
+
+
+ {#if returnTo}{/if} + {#if mode === "register" && showName} + + {/if} + {#if mode === "sign-in" || mode === "register" || mode === "recover"} + + {/if} + {#if mode === "sign-in" || mode === "register" || mode === "reset"} + + {/if} + {#if mode === "register" || mode === "reset"} + + {/if} + {#if mode === "mfa"} + + {/if} + {#if mode === "sign-in" && showRemember} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AuthSplitLayout.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AuthSplitLayout.wrn new file mode 100644 index 00000000..771c2902 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AuthSplitLayout.wrn @@ -0,0 +1,83 @@ +component AuthSplitLayout { + props { + size = "default" + color = "primary" + eyebrow = "Secure identity" + title = "Welcome back" + description = "" + brand = "Police Management System" + features = [] + class = "" + } + + view { +
+
+
+ + {brand}Unified identity and access +
+
+ + {eyebrow} + +

{title}

+ {#if description} +

{description}

+ {/if} +
+ {#each features as item} +
+ + {item.label} + {#if item.description} + {item.description} + {/if} + +
+ {/each} +
+ +
+ + Authorised access only · Activity may be monitored and audited. + +
+
+
+ +
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AvatarGroup.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AvatarGroup.wrn new file mode 100644 index 00000000..45623306 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/AvatarGroup.wrn @@ -0,0 +1,151 @@ +component AvatarGroup { + props { + items = [] + size = "md" + color = "primary" + variant = "solid" + shape = "circle" + layout = "stack" + maxVisible = 4 + columns = 3 + borderColor = "" + showTooltips = true + overflowLabel = "Show remaining members" + class = "" + + @event overflow = function + } + + state overflowOpen = false + + functions { + function visibleMembers() { + return items.slice(0, Number(maxVisible)) + } + + function hiddenMembers() { + return items.slice(Number(maxVisible)) + } + + function toggleOverflow(sourceEvent, root, customEvent) { + overflowOpen = !overflowOpen + root = sourceEvent.currentTarget.closest("[data-wrn-avatar-group]") + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("overflow", true, false, { + component: "AvatarGroup", + open: overflowOpen, + hiddenCount: hiddenMembers().length + }) + root.dispatchEvent(customEvent) + } + } + + view { +
+
+ {#each visibleMembers() as item} + + + {#if item.src} + {item.alt || item.name || ''} + {:else if item.initials} + + {:else} + + {/if} + + + {#if showTooltips && (item.tooltip || item.name)} + + {item.tooltip || item.name} + + {/if} + + {/each} + + {#if hiddenMembers().length > 0} + + + + + {#each hiddenMembers() as item} + + + {#if item.src} + + {:else} + {item.initials || '?'} + {/if} + + {item.name || item.alt || item.initials || 'Team member'} + + {/each} + + + {/if} +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/BackToTop.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/BackToTop.wrn new file mode 100644 index 00000000..42d2e157 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/BackToTop.wrn @@ -0,0 +1,69 @@ +component BackToTop { + props { + threshold = 500 + label = "Back to top" + ariaLabel = "Scroll back to top" + icon = "icon-[lucide--arrow-up]" + position = "right" + offset = "md" + behavior = "smooth" + showProgress = false + size = "default" + color = "primary" + variant = "solid" + class = "" + } + + state visible = false + state progress = 0 + + view { + + } + + style { + .wire-back-to-top-progress { + background: conic-gradient( + currentColor var(--wire-back-to-top-progress), + transparent var(--wire-back-to-top-progress) + ); + opacity: 0.22; + } + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Badge.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Badge.wrn new file mode 100644 index 00000000..e5eb1c9b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Badge.wrn @@ -0,0 +1,102 @@ +component Badge { + props { + label = "Badge" + size = "md" + color = "primary" + variant = "solid" + shape = "pill" + class = "" + + icon = "" + iconPosition = "start" + dot = false + dotOnly = false + dotLabel = "Status" + animated = false + + avatarSrc = "" + avatarAlt = "" + dismissible = false + dismissLabel = "Remove badge" + truncate = false + maxWidth = "12rem" + + anchorLabel = "" + anchorIcon = "" + placement = "inline" + anchorLabelText = "Badge anchor" + + @event dismiss = function + } + + state visible = true + + functions { + function dismissBadge(sourceEvent, root, customEvent) { + visible = false + root = sourceEvent.currentTarget.closest("[data-wrn-badge]") + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("dismiss", true, false, { + component: "Badge", + label: label + }) + root.dispatchEvent(customEvent) + } + } + + view { + + {#if anchorLabel || anchorIcon} + + {/if} + + + {#if animated} + + {/if} + {#if avatarSrc} + {avatarAlt} + {/if} + {#if dot || dotOnly} + + {/if} + {#if icon && iconPosition === "start"} + + {/if} + {#if !dotOnly} + + {label} + + {/if} + {#if icon && iconPosition === "end"} + + {/if} + {#if dismissible} + + {/if} + + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Blockquote.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Blockquote.wrn new file mode 100644 index 00000000..dc476675 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Blockquote.wrn @@ -0,0 +1,67 @@ +component Blockquote { + props { + quote = "I just wanted to say that I'm very happy with my purchase so far. The documentation is outstanding - clear and detailed." + citation = "" + citationTitle = "" + citationUrl = "" + avatarSrc = "" + avatarAlt = "" + size = "md" + color = "primary" + align = "left" + variant = "default" + quoteMark = true + italic = true + class = "" + } + + view { +
+
+ {#if quoteMark} + + {/if} + +
+ {#if quote} +

{quote}

+ {:else} + + {/if} +
+
+ + {#if citation || citationTitle || avatarSrc} +
+ {#if avatarSrc} + {avatarAlt} + {/if} + + + {#if citation} + {#if citationUrl} + {citation} + {:else} + {citation} + {/if} + {/if} + {#if citationTitle}{citationTitle}{/if} + +
+ {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Breadcrumb.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Breadcrumb.wrn new file mode 100644 index 00000000..1fee40b5 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Breadcrumb.wrn @@ -0,0 +1,19 @@ +component Breadcrumb { + props { + @event navigate = function + @event click = function + size = "default" + color = "primary" + label = "Breadcrumb" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ButtonGroup.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ButtonGroup.wrn new file mode 100644 index 00000000..7430aba7 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ButtonGroup.wrn @@ -0,0 +1,89 @@ +component ButtonGroup { + props { + @event click = function + @event select = function + @event change = function + items = [] + value = "" + size = "md" + color = "primary" + variant = "default" + orientation = "horizontal" + responsive = false + attached = true + selectable = false + toolbar = false + disabled = false + ariaLabel = "Button group" + class = "" + } + + state selectedValue = value + + functions { + function itemValue(item, index) { + return item.value || item.label || String(index) + } + + function selectItem(item, index) { + previousValue = selectedValue + nextValue = itemValue(item, index) + + $emit("select", { + value: nextValue, + previousValue: previousValue, + item: item, + index: index + }) + + if (selectable && previousValue !== nextValue) { + selectedValue = nextValue + $emit("change", { + value: nextValue, + previousValue: previousValue, + item: item, + index: index + }) + } + } + } + + view { +
+ {#if items} + {#each items as item, index} + + {/each} + {/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/CTASection.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/CTASection.wrn new file mode 100644 index 00000000..36453a83 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/CTASection.wrn @@ -0,0 +1,150 @@ +component CTASection { + props { + eyebrow = "" + title = "Ready to get started?" + description = "" + icon = "" + align = "center" + size = "default" + color = "primary" + variant = "solid" + primaryLabel = "Get started" + primaryHref = "#" + primaryIcon = "" + secondaryLabel = "" + secondaryHref = "" + secondaryIcon = "" + backgroundImage = "" + maxWidth = "xl" + class = "" + } + + view { +
+
+ {#if backgroundImage} + + {/if} + + + + +
+
+ {#if icon} + + + + {/if} + + {#if eyebrow} +

+ {eyebrow} +

+ {/if} + +

+ {title} +

+ + {#if description} +

+ {description} +

+ {/if} + + +
+ + + + + + +
+ + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Card.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Card.wrn new file mode 100644 index 00000000..ecbcfc7c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Card.wrn @@ -0,0 +1,284 @@ +component Card { + props { + @event click = function + @event action = function + @event navigate = function + @event dismiss = function + @event load = function + @event error = function + title = "Card title" + subtitle = "" + description = "" + header = "" + footer = "" + imageSrc = "" + imageAlt = "" + imagePosition = "top" + actionLabel = "" + actionHref = "" + headerActions = [] + navigation = [] + activeNav = "" + mobileNavigation = false + alertTitle = "" + alertDescription = "" + empty = false + emptyTitle = "No data to show" + emptyIcon = "icon-[lucide--inbox]" + items = [] + size = "md" + color = "primary" + variant = "default" + layout = "vertical" + align = "left" + hover = "none" + scrollable = false + maxHeight = "18rem" + dismissible = false + ariaLabel = "" + class = "" + } + + state dismissed = false + + view { +
+ {#if items.length > 0} +
+ {#each items as item, itemIndex} +
+ {#if item.imageSrc || item.image} +
+ {item.imageAlt || item.alt || ""} +
+ {/if} + +
+ {#if item.title || item.label} +

{item.title || item.label}

+ {/if} + {#if item.subtitle} +

{item.subtitle}

+ {/if} + {#if item.description} +

{item.description}

+ {/if} + {#if item.actionLabel || item.href} + + {item.actionLabel || "Learn more"} + + + {/if} +
+
+ {/each} +
+ {:else} +
+ {#if imageSrc && imagePosition === "overlay"} +
+ {imageAlt} + +
+ {/if} + + {#if imageSrc && (imagePosition === "top" || imagePosition === "left")} +
+ {imageAlt} +
+ {/if} + +
+ {#if header || title || subtitle || headerActions.length > 0 || dismissible} +
+
+ {#if header} +

{header}

+ {/if} + {#if title} +

{title}

+ {/if} + {#if subtitle} +

{subtitle}

+ {/if} +
+ + {#if headerActions.length > 0 || dismissible} +
+ {#each headerActions as headerAction, actionIndex} + + {/each} + + {#if dismissible} + + {/if} +
+ {/if} +
+ {/if} + + {#if navigation.length > 0} + + {/if} + + {#if alertTitle || alertDescription} +
+ {#if alertTitle} + {alertTitle} + {/if} + {#if alertDescription} +

{alertDescription}

+ {/if} +
+ {/if} + +
+ {#if empty} +
+ +

{emptyTitle}

+
+ {:else} + {#if description} +

{description}

+ {/if} + + {/if} +
+ + {#if footer || actionLabel} + + {/if} +
+ + {#if imageSrc && (imagePosition === "bottom" || imagePosition === "right")} +
+ {imageAlt} +
+ {/if} +
+ {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Chart.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Chart.wrn new file mode 100644 index 00000000..d491c5ae --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Chart.wrn @@ -0,0 +1,22 @@ +component Chart { + props { + @event select = function + @event dataPointClick = function + @event legendToggle = function + size = "default" + color = "primary" + title = "Chart" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ChatBubble.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ChatBubble.wrn new file mode 100644 index 00000000..947f6995 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ChatBubble.wrn @@ -0,0 +1,147 @@ +component ChatBubble { + props { + @event action = function + @event messageClick = function + @event avatarClick = function + @event linkClick = function + size = "default" + color = "primary" + title = "" + description = "" + items = [] + oneSided = false + showAvatars = false + showMetadata = false + ariaLabel = "Conversation" + variant = "default" + class = "" + } + + functions { + function messageDirection(item) { + return item.direction === "outgoing" ? "outgoing" : "incoming" + } + + function selectMessage(item, index) { + $emit("messageClick", { + item: item, + index: index, + direction: messageDirection(item) + }) + } + + function selectAvatar(sourceEvent, item, index) { + sourceEvent.stopPropagation() + $emit("avatarClick", { + item: item, + index: index, + direction: messageDirection(item) + }) + } + + function selectLink(sourceEvent, link, item, index) { + sourceEvent.stopPropagation() + $emit("linkClick", { + link: link, + item: item, + index: index + }) + } + + function selectAction(sourceEvent, item, index) { + sourceEvent.stopPropagation() + $emit("action", { + action: item.action || "retry", + item: item, + index: index + }) + } + } + + view { +
+ {#if title || description} +
+ {#if title}

{title}

{/if} + {#if description}

{description}

{/if} +
+ {/if} + + {#if items.length} +
+ {#each items as item, index} +
+
+ {#if showAvatars && (item.avatarSrc || item.avatarFallback)} + + {/if} + +
+ {#if item.title}

{item.title}

{/if} + {#if item.text}

{item.text}

{/if} + {#if item.bullets && item.bullets.length} +
    + {#each item.bullets as bullet}
  • {bullet}
  • {/each} +
+ {/if} + {#if item.links && item.links.length} + + {/if} +
+
+ + {#if showMetadata && (item.timestamp || item.status || item.actionLabel)} +
+ {#if item.statusIcon}{/if} + {#if item.status}{item.status}{/if} + {#if item.timestamp}{/if} + {#if item.actionLabel} + + {/if} +
+ {/if} +
+ {/each} +
+ {/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Checkbox.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Checkbox.wrn new file mode 100644 index 00000000..b945892e --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Checkbox.wrn @@ -0,0 +1,173 @@ +component Checkbox { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Checkbox" + hiddenLabel = false + placeholder = "" + variant = "normal" + icon = "" + iconPosition = "start" + value = "on" + values = [] + options = [] + checked = false + indeterminate = false + orientation = "vertical" + card = false + rightAligned = false + list = false + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { checked: sourceEvent.currentTarget.checked, value: sourceEvent.currentTarget.value, values: values, name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
+ {#if options.length || cornerHint} + + {label} + + {#if cornerHint} + + {cornerHint} + + {/if} + {/if} +
+ {#if options.length} +
+ {#each options as option} + + {/each} +
+ {:else} +
+ +
+ {/if} + {#if helperText} + + {helperText} + + {/if} + + {error} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Clipboard.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Clipboard.wrn new file mode 100644 index 00000000..09893a4a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Clipboard.wrn @@ -0,0 +1,22 @@ +component Clipboard { + props { + @event copy = function + @event success = function + @event error = function + size = "default" + color = "primary" + title = "Clipboard" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Collapse.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Collapse.wrn new file mode 100644 index 00000000..531c31f1 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Collapse.wrn @@ -0,0 +1,95 @@ +component Collapse { + props { + @event toggle = function + @event open = function + @event close = function + size = "default" + color = "primary" + items = [] + multiple = false + mode = "panel" + initialOpenIndexes = [] + ariaLabel = "Collapsible content" + class = "" + } + + state openIndexes = initialOpenIndexes + + functions { + function isOpen(index) { + return openIndexes.includes(index) + } + + function toggleItem(index, item, opening) { + if (item.disabled) { + return + } + opening = !isOpen(index) + if (opening) { + if (multiple) { + openIndexes = openIndexes.concat(index) + } else { + openIndexes = [index] + } + $emit("open", { index: index, item: item }) + } else { + openIndexes = openIndexes.filter((openIndex) => openIndex !== index) + $emit("close", { index: index, item: item }) + } + $emit("toggle", { + index: index, + item: item, + open: opening, + openIndexes: openIndexes + }) + } + } + + view { +
+ {#each items as item, index} +
+ {#if mode === "inline" && item.preview} +

{item.preview}

+ {/if} + + + +
+
+ {#if item.title}

{item.title}

{/if} + {#if item.content}

{item.content}

{/if} + {#if item.links && item.links.length} + + {/if} +
+
+
+ {/each} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ColorPicker.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ColorPicker.wrn new file mode 100644 index 00000000..0ba19a3a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ColorPicker.wrn @@ -0,0 +1,38 @@ +component ColorPicker { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Color" + hiddenLabel = false + placeholder = "" + value = "#2563eb" + icon = "" + iconPosition = "start" + helperText = "" + cornerHint = "" + error = "" + inline = false + variant = "normal" + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
{#if icon}{/if}{value}
+ {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Columns.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Columns.wrn new file mode 100644 index 00000000..96ac7ad1 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Columns.wrn @@ -0,0 +1,35 @@ +component Columns { + props { + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + + view { +
+ +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Combobox.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Combobox.wrn new file mode 100644 index 00000000..7f82992b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Combobox.wrn @@ -0,0 +1,386 @@ +component ComboBox { + props { + size = "default" + color = "primary" + label = "ComboBox" + name = "" + value = "" + options = [] + groups = [] + placeholder = "Search or select an option" + searchPlaceholder = "Start typing…" + clearable = true + allowCustomValue = false + disabled = false + required = false + invalid = false + validationMessage = "" + helpText = "" + loading = false + loadingLabel = "Loading suggestions…" + emptyLabel = "No matching options" + clearLabel = "Clear value" + toggleLabel = "Toggle suggestions" + searchMode = "contains" + searchFields = "label,description" + minSearchLength = 0 + searchResultLimit = 0 + optionTemplate = "default" + defaultOpen = false + closeOnSelect = true + fixed = false + placement = "bottom" + autocomplete = "off" + remote = false + remoteUrl = "" + remoteQueryParam = "q" + remoteDebounce = 250 + remoteAutoLoad = true + infinite = false + hasMore = false + page = 1 + loadMoreLabel = "Load more" + class = "" + @event search = function + @event select = function + @event change = function + @event clear = function + @event open = function + @event close = function + @event load = function + @event error = function + } + + state open = defaultOpen + state query = "" + state selectedValue = value + state activeIndex = -1 + + functions { + function allOptions() { + return [...groups.flatMap((group) => group.options || []), ...options] + } + + function searchableText(option) { + return ((option.label || "") + " " + (option.description || "")).toLowerCase() + } + + function matches(option) { + if (!query || query.length < minSearchLength) { + return true + } + if (searchMode === "startsWith") { + return searchableText(option).startsWith(query.toLowerCase()) + } + if (searchMode === "exact") { + return searchableText(option) === query.toLowerCase() + } + return searchableText(option).includes(query.toLowerCase()) + } + + function matchingOptions(list) { + return list.filter((option) => matches(option)) + } + + function visibleOptions(list) { + if (searchResultLimit > 0) { + return matchingOptions(list).slice(0, searchResultLimit) + } + return matchingOptions(list) + } + + function flatVisibleOptions() { + return visibleOptions(allOptions()) + } + + function isSelected(option) { + return selectedValue === option.value + } + + function selectedOptions() { + return allOptions().filter((option) => isSelected(option)) + } + + function selectedText() { + return selectedOptions().length ? selectedOptions()[0].label : selectedValue + } + + function inputText() { + return query || selectedText() + } + + function shouldShowDropdown() { + if (!open) { + return false + } + if (loading) { + return true + } + if (remote && query.length !== 0 && query.length < minSearchLength) { + return true + } + if (flatVisibleOptions().length) { + return true + } + return infinite && hasMore + } + + function canSelect(option) { + return !option.disabled + } + + function chooseOption(option) { + if (!canSelect(option)) { + return + } + selectedValue = option.value + query = option.label + activeIndex = optionIndex(option) + if (closeOnSelect) { + open = false + } + } + + function updateQuery(event) { + query = event.target.value + selectedValue = allowCustomValue ? event.target.value : "" + open = true + activeIndex = flatVisibleOptions().length ? 0 : -1 + } + + function clearValue(event) { + if (event) { + event.stopPropagation() + } + query = "" + selectedValue = "" + activeIndex = -1 + open = false + } + + function openDropdown() { + if (!disabled) { + open = true + activeIndex = flatVisibleOptions().length ? 0 : -1 + } + } + + function closeDropdown() { + open = false + } + + function toggle() { + if (open) { + closeDropdown() + } else { + openDropdown() + } + } + + function setValue(nextValue) { + selectedValue = nextValue + query = "" + } + + function moveActive(direction) { + if (!flatVisibleOptions().length) { + return + } + activeIndex = (activeIndex + direction + flatVisibleOptions().length) % flatVisibleOptions().length + } + + function handleKeydown(event) { + if (disabled) { + return + } + if (event.key === "ArrowDown") { + event.preventDefault() + openDropdown() + moveActive(1) + } else if (event.key === "ArrowUp") { + event.preventDefault() + openDropdown() + moveActive(-1) + } else if (event.key === "Enter" && open && activeIndex >= 0) { + event.preventDefault() + chooseOption(flatVisibleOptions()[activeIndex]) + } else if (event.key === "Escape") { + closeDropdown() + } else if (event.key === "Home" && open) { + event.preventDefault() + activeIndex = 0 + } else if (event.key === "End" && open) { + event.preventDefault() + activeIndex = flatVisibleOptions().length - 1 + } + } + + function optionIndex(option) { + return flatVisibleOptions().findIndex((item) => item.value === option.value) + } + } + + view { +
+ + +
+ + + + + +
+ +
+
Enter at least {minSearchLength} characters.
+
+ + {loadingLabel} +
+ +
+ {#each groups as group} + {#if visibleOptions(group.options || []).length} +
+
{group.label}
+ {#each group.options || [] as option} + + {/each} +
+ {/if} + {/each} + + {#each options as option} + + {/each} +
+ + +
+ + {#if !allowCustomValue} + + {/if} + + {#if helpText && !validationMessage}{helpText}{/if} + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Confetti.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Confetti.wrn new file mode 100644 index 00000000..26bbf788 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Confetti.wrn @@ -0,0 +1,21 @@ +component Confetti { + props { + @event start = function + @event complete = function + size = "default" + color = "primary" + title = "Confetti" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Container.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Container.wrn new file mode 100644 index 00000000..bcc3a50f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Container.wrn @@ -0,0 +1,46 @@ +component Container { + props { + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + + view { +
+ +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ContextMenu.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ContextMenu.wrn new file mode 100644 index 00000000..7a8b1264 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ContextMenu.wrn @@ -0,0 +1,22 @@ +component ContextMenu { + props { + @event open = function + @event close = function + @event select = function + size = "default" + color = "primary" + title = "Context Menu" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { +
+
{title}
+ {#if description}

{description}

{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/CopyMarkup.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/CopyMarkup.wrn new file mode 100644 index 00000000..ab506a30 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/CopyMarkup.wrn @@ -0,0 +1,23 @@ +component CopyMarkup { + props { + @event copy = function + @event success = function + @event error = function + size = "default" + color = "primary" + label = "Copy Markup" + name = "" + value = "" + placeholder = "" + type = "text" + min = "" + max = "" + step = "" + disabled = false + required = false + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/CustomScrollbar.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/CustomScrollbar.wrn new file mode 100644 index 00000000..37ace07c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/CustomScrollbar.wrn @@ -0,0 +1,14 @@ +component CustomScrollbar { + props { + @event scroll = function + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + view { +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DataMap.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DataMap.wrn new file mode 100644 index 00000000..49a30b5e --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DataMap.wrn @@ -0,0 +1,21 @@ +component DataMap { + props { + @event select = function + @event change = function + size = "default" + color = "primary" + title = "Data Map" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DataTable.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DataTable.wrn new file mode 100644 index 00000000..3ff347ea --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DataTable.wrn @@ -0,0 +1,19 @@ +component DataTable { + props { + @event sort = function + @event select = function + @event change = function + @event rowClick = function + @event pageChange = function + size = "default" + color = "primary" + caption = "Data Table" + columns = [] + rows = [] + striped = true + class = "" + } + view { +
{#each columns as column}{/each}{#each rows as row}{#each columns as column}{/each}{/each}
{caption}
{column.label}
{row[column.key]}
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DatePicker.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DatePicker.wrn new file mode 100644 index 00000000..b7682e5f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DatePicker.wrn @@ -0,0 +1,59 @@ +component DatePicker { + props { + @event input = function + @event change = function + @event open = function + @event close = function + @event focus = function + @event blur = function + @event invalid = function + size = "default" + color = "primary" + label = "Date Picker" + id = "" + name = "" + value = "" + placeholder = "" + type = "date" + locale = "en-US" + firstDayOfWeek = 0 + months = [{ label: "Jan", value: "01" }, { label: "Feb", value: "02" }, { label: "Mar", value: "03" }, { label: "Apr", value: "04" }, { label: "May", value: "05" }, { label: "Jun", value: "06" }, { label: "Jul", value: "07" }, { label: "Aug", value: "08" }, { label: "Sep", value: "09" }, { label: "Oct", value: "10" }, { label: "Nov", value: "11" }, { label: "Dec", value: "12" }] + days = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31] + years = [2024, 2025, 2026, 2027, 2028, 2029, 2030] + min = "" + max = "" + step = "" + helperText = "" + cornerHint = "" + error = "" + variant = "normal" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + state currentValue = value + state selectedYear = value ? value.split("-")[0] : "" + state selectedMonth = value ? value.split("-")[1] : "" + state selectedDay = value ? value.split("-")[2] : "" + state expanded = false + functions { + function openCalendar(sourceEvent) { expanded = true; $emit("open", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function updateDate(part, nextValue, sourceEvent, nextDate, detail) { if (part === "year") { selectedYear = String(nextValue) } if (part === "month") { selectedMonth = String(nextValue).padStart(2, "0") } if (part === "day") { selectedDay = String(nextValue).padStart(2, "0") } if (!selectedYear || !selectedMonth || !selectedDay) { return } nextDate = selectedYear + "-" + selectedMonth + "-" + selectedDay; if ((min && nextDate < min) || (max && nextDate > max)) { return } currentValue = nextDate; detail = { value: currentValue, year: selectedYear, month: selectedMonth, day: selectedDay, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function finishDate(sourceEvent) { if (!currentValue) { return } expanded = false; $emit("close", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function selectDay(sourceEvent, root, input, nextDate, trigger, detail) { root = sourceEvent.currentTarget.closest(".wire-next--date-picker"); input = root.querySelector(".wire-next__picker-value"); nextDate = input.getAttribute("value").slice(0, 5) + root.querySelector("select").getAttribute("value") + "-" + sourceEvent.currentTarget.dataset.value; currentValue = nextDate; input.setAttribute("value", nextDate); trigger = root.querySelector(".wire-next__date-trigger span"); if (trigger) { trigger.replaceChildren(nextDate) } sourceEvent.currentTarget.setAttribute("aria-pressed", "true"); detail = { value: nextDate, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function clearDate(sourceEvent, detail) { if (disabled || readonly) { return } currentValue = ""; detail = { value: currentValue, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function handleFocus(sourceEvent) { $emit("focus", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleBlur(sourceEvent) { $emit("blur", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleInvalid(sourceEvent) { $emit("invalid", { name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
{#if currentValue && !readonly && !disabled}{/if}
+ + {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DeviceFrame.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DeviceFrame.wrn new file mode 100644 index 00000000..f2d3d891 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DeviceFrame.wrn @@ -0,0 +1,31 @@ +component DeviceFrame { + props { + @event change = function + @event rotate = function + size = "default" + color = "primary" + title = "Device Frame" + description = "" + items = [] + variant = "default" + device = "phone" + orientation = "portrait" + src = "" + srcdoc = "" + frameTitle = "Device preview" + showToolbar = true + allow = "" + class = "" + } + state currentOrientation = orientation + functions { + function setDevice(nextDevice, sourceEvent) { $emit("change", { device: nextDevice, orientation: currentOrientation, sourceEvent: sourceEvent }) } + function rotateFrame(sourceEvent) { currentOrientation = currentOrientation === "portrait" ? "landscape" : "portrait"; $emit("rotate", { device: device, orientation: currentOrientation, sourceEvent: sourceEvent }); $emit("change", { device: device, orientation: currentOrientation, sourceEvent: sourceEvent }) } + } + view { +
+
{#if title}{title}{/if}{#if description}

{description}

{/if}
{#if showToolbar}{/if}
+
{#if src || srcdoc}{:else}
{/if}
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Divider.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Divider.wrn new file mode 100644 index 00000000..b7a19a9f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Divider.wrn @@ -0,0 +1,69 @@ +component Divider { + props { + size = "default" + color = "primary" + label = "" + orientation = "horizontal" + class = "" + } + + view { +
+ {#if orientation === "vertical"} + + {:else} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DragAndDrop.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DragAndDrop.wrn new file mode 100644 index 00000000..944dec48 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/DragAndDrop.wrn @@ -0,0 +1,25 @@ +component DragAndDrop { + props { + @event dragStart = function + @event dragEnd = function + @event dragEnter = function + @event dragLeave = function + @event drop = function + @event change = function + size = "default" + color = "primary" + title = "Drag And Drop" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Drawer.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Drawer.wrn new file mode 100644 index 00000000..641cef87 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Drawer.wrn @@ -0,0 +1,21 @@ +component Drawer { + props { + @event open = function + @event close = function + size = "default" + color = "primary" + title = "Drawer" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Dropdown.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Dropdown.wrn new file mode 100644 index 00000000..f73c1a6c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Dropdown.wrn @@ -0,0 +1,53 @@ +component Dropdown { + props { + @event toggle = function + @event open = function + @event close = function + @event select = function + size = "default" + color = "primary" + label = "Open menu" + items = [] + placement = "end" + class = "" + } + + functions { + function toggleMenu(event) { + $emit("toggle", { open: event.currentTarget.open }) + $emit(event.currentTarget.open ? "open" : "close", { source: "trigger" }) + } + + function selectItem(item) { + $emit("select", { item: item, value: item.value || "" }) + } + } + + view { +
+ + + + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FeatureCard.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FeatureCard.wrn new file mode 100644 index 00000000..93eb1906 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FeatureCard.wrn @@ -0,0 +1,113 @@ +component FeatureCard { + props { + icon = "" + title = "Feature" + description = "" + href = "" + actionLabel = "Learn more" + actionIcon = "" + badge = "" + badgeColor = "primary" + size = "default" + color = "primary" + variant = "default" + hover = "lift" + align = "left" + disabled = false + class = "" + } + + view { +
+
+
+ + {#if icon} + + {/if} +
+ + {#if badge} + + {/if} +
+ +

+ {title} +

+ + {#if description} +

+ {description} +

+ {/if} + + + +
+ + + {#if href && actionLabel} + + {/if} +
+ + {#if href} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FeatureGrid.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FeatureGrid.wrn new file mode 100644 index 00000000..cec10f97 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FeatureGrid.wrn @@ -0,0 +1,55 @@ +component FeatureGrid { + props { + color = "primary" + size = "default" + columns = 3 + tabletColumns = 2 + mobileColumns = 1 + gap = "md" + minItemWidth = "" + equalHeight = true + align = "stretch" + maxWidth = "full" + class = "" + } + + view { +
+ +
+ } + + style { + .wire-feature-grid-autofit { + grid-template-columns: repeat(auto-fit, minmax(var(--wire-feature-grid-min), 1fr)); + } + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FeatureIconCard.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FeatureIconCard.wrn new file mode 100644 index 00000000..1b985d39 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FeatureIconCard.wrn @@ -0,0 +1,78 @@ +component FeatureIconCard { + props { + icon = "icon-[lucide--sparkles]" + iconSize = "md" + iconVariant = "soft" + title = "Feature" + description = "" + href = "" + actionLabel = "Explore" + badge = "" + size = "default" + color = "primary" + variant = "default" + align = "left" + hover = "lift" + class = "" + } + + view { +
+
+ + + {#if badge} + + {badge} + + {/if} +
+ +

{title}

+ + {#if description} +

{description}

+ {/if} + + + + {#if href} + + {/if} + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FileInput.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FileInput.wrn new file mode 100644 index 00000000..b3ed2183 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FileInput.wrn @@ -0,0 +1,52 @@ +component FileInput { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event select = function + @event clear = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "File" + hiddenLabel = false + placeholder = "Choose a file" + value = "" + icon = "icon-[lucide--upload]" + iconPosition = "start" + accept = "" + multiple = false + helperText = "" + cornerHint = "" + error = "" + inline = false + variant = "normal" + readonly = false + disabled = false + required = false + class = "" + } + state selectedName = "" + functions { + function handleChange(sourceEvent) { + sourceEvent.stopPropagation() + selectedName = sourceEvent.currentTarget.files && sourceEvent.currentTarget.files.length ? sourceEvent.currentTarget.files[0].name : "" + $emit("input", { files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent }) + $emit("change", { files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent }) + if (selectedName) $emit("select", { files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent }) + else $emit("clear", { name: name, sourceEvent: sourceEvent }) + } + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
{#if icon}{/if}{selectedName || value || placeholder}
+ {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FileUpload.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FileUpload.wrn new file mode 100644 index 00000000..207d3571 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FileUpload.wrn @@ -0,0 +1,26 @@ +component FileUpload { + props { + @event select = function + @event upload = function + @event progress = function + @event success = function + @event error = function + @event cancel = function + @event remove = function + size = "default" + color = "primary" + title = "File Upload" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FileUploadProgress.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FileUploadProgress.wrn new file mode 100644 index 00000000..329a5859 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/FileUploadProgress.wrn @@ -0,0 +1,37 @@ +component FileUploadProgress { + props { + @event cancel = function + @event retry = function + @event complete = function + size = "default" + color = "primary" + label = "Progress" + value = 50 + max = 100 + showValue = true + fileName = "" + fileSize = "" + uploadedSize = "" + status = "uploading" + cancelLabel = "Cancel upload" + retryLabel = "Retry upload" + class = "" + } + state currentValue = value + state currentStatus = status + functions { + function percent() { if (!Number(max)) { return 0 } return Math.max(0, Math.min(100, Math.round(Number(currentValue) / Number(max) * 100))) } + function detail(sourceEvent) { return { value: currentValue, max: max, percent: percent(), status: currentStatus, fileName: fileName, sourceEvent: sourceEvent } } + function cancelUpload(sourceEvent) { currentStatus = "cancelled"; $emit("cancel", detail(sourceEvent)) } + function retryUpload(sourceEvent) { currentValue = 0; currentStatus = "uploading"; $emit("retry", detail(sourceEvent)) } + function completeUpload(sourceEvent) { currentValue = max; currentStatus = "complete"; $emit("complete", detail(sourceEvent)) } + } + view { +
+
{#if fileName}{fileName}{#if uploadedSize || fileSize}{uploadedSize}{#if uploadedSize && fileSize} of {/if}{fileSize}{:else}{label}{/if}{:else}{label}{/if}{#if showValue}{percent()}%{/if}
+ +
{#if currentStatus === "uploading"}Uploading securely…{:else if currentStatus === "complete"}Upload complete{:else if currentStatus === "error"}Upload failed{:else}Upload cancelled{/if}
+
{#if currentStatus === "uploading"}{/if}{#if currentStatus === "error" || currentStatus === "cancelled"}{/if}
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Footer.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Footer.wrn new file mode 100644 index 00000000..e0f3ac1d --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Footer.wrn @@ -0,0 +1,144 @@ +component Footer { + props { + @event select = function + @event action = function + size = "default" + color = "primary" + label = "Footer navigation" + items = [] + columns = 3 + maxWidth = "compact" + copyright = "" + class = "" + } + + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Grid.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Grid.wrn new file mode 100644 index 00000000..b76a5447 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Grid.wrn @@ -0,0 +1,40 @@ +component Grid { + props { + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + + view { +
+ +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Hero.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Hero.wrn new file mode 100644 index 00000000..7613a2b6 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Hero.wrn @@ -0,0 +1,149 @@ +component Hero { + props { + eyebrow = "" + title = "Build something remarkable" + highlight = "" + description = "" + align = "left" + size = "default" + color = "primary" + variant = "default" + primaryLabel = "" + primaryHref = "" + primaryIcon = "" + secondaryLabel = "" + secondaryHref = "" + secondaryIcon = "" + tertiaryLabel = "" + tertiaryHref = "" + badges = [] + trustItems = [] + maxWidth = "xl" + class = "" + } + + view { +
+
+ {#if variant === "gradient"} + + {/if} + +
+ + + {#if eyebrow} +
+ + {eyebrow} +
+ {/if} + +

+ {title} + {#if highlight} + + {highlight} + + {/if} +

+ + {#if description} +

+ {description} +

+ {/if} + + {#if badges.length > 0} +
+ {#each badges as badge} + + {/each} +
+ {/if} + +
+ + + +
+ + {#if trustItems.length > 0} +
+ {#each trustItems as item} + + + {item.label || item.title || item} + + {/each} +
+ {/if} + + + +
+ +
+ +
+ + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/HeroActions.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/HeroActions.wrn new file mode 100644 index 00000000..28b0cc44 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/HeroActions.wrn @@ -0,0 +1,52 @@ +component HeroActions { + props { + actions = [] + align = "left" + orientation = "horizontal" + stackOnMobile = true + fullWidthMobile = true + size = "default" + color = "primary" + class = "" + } + + view { +
+ {#each actions as action, index} + {#if action.label} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Image.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Image.wrn new file mode 100644 index 00000000..881d5229 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Image.wrn @@ -0,0 +1,47 @@ +component Image { + props { + size = "default" + color = "primary" + src = "" + alt = "" + width = "" + height = "" + loading = "lazy" + rounded = false + class = "" + } + + view { +
+ {#if src} + {alt} + {:else} + + {/if} + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Input.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Input.wrn new file mode 100644 index 00000000..3e12c986 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Input.wrn @@ -0,0 +1,92 @@ +component Input { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event invalid = function + @event keydown = function + @event keyup = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Input" + hiddenLabel = false + placeholder = "" + value = "" + type = "text" + variant = "normal" + icon = "" + iconPosition = "start" + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + autocomplete = "" + inputmode = "" + minlength = "" + maxlength = "" + pattern = "" + min = "" + max = "" + step = "" + class = "" + } + functions { + function detail(sourceEvent) { + return { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent } + } + function handleInput(sourceEvent) { sourceEvent.stopPropagation(); $emit("input", detail(sourceEvent)) } + function handleChange(sourceEvent) { sourceEvent.stopPropagation(); $emit("change", detail(sourceEvent)) } + function handleFocus(sourceEvent) { sourceEvent.stopPropagation(); $emit("focus", detail(sourceEvent)) } + function handleBlur(sourceEvent) { sourceEvent.stopPropagation(); $emit("blur", detail(sourceEvent)) } + function handleInvalid(sourceEvent) { sourceEvent.stopPropagation(); $emit("invalid", { value: sourceEvent.currentTarget.value, name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } + function handleKeydown(sourceEvent) { sourceEvent.stopPropagation(); $emit("keydown", { key: sourceEvent.key, value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + function handleKeyup(sourceEvent) { sourceEvent.stopPropagation(); $emit("keyup", { key: sourceEvent.key, value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + } + view { +
+
+ + {#if cornerHint}{cornerHint}{/if} +
+
+ {#if icon}{/if} + + {#if variant === "floating"}{label}{/if} +
+ {#if helperText}{helperText}{/if} + {error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/InputGroup.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/InputGroup.wrn new file mode 100644 index 00000000..aea3fd7a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/InputGroup.wrn @@ -0,0 +1,51 @@ +component InputGroup { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event submit = function + @event action = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Input group" + hiddenLabel = false + value = "" + placeholder = "" + type = "text" + startText = "" + endText = "" + icon = "" + iconPosition = "start" + actionLabel = "" + helperText = "" + cornerHint = "" + error = "" + inline = false + variant = "normal" + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + function handleKeydown(sourceEvent) { if (sourceEvent.key === "Enter") { sourceEvent.stopPropagation(); $emit("submit", { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } } + function handleAction(sourceEvent) { $emit("action", { name: name, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if startText}{startText}{/if} + {#if icon}{/if} + + {#if endText}{endText}{/if} + {#if actionLabel}{/if} +
+ {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/InputNumber.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/InputNumber.wrn new file mode 100644 index 00000000..226922fd --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/InputNumber.wrn @@ -0,0 +1,623 @@ +component InputNumber { + props { + size = "default" + color = "primary" + variant = "default" + class = "" + + id = "" + name = "quantity" + value = 0 + min = "" + max = "" + step = 1 + precision = "auto" + + label = "" + description = "" + helpText = "" + error = "" + invalid = false + + prefix = "" + suffix = "" + placeholder = "" + autocomplete = "off" + inputMode = "decimal" + ariaLabel = "" + + required = false + disabled = false + inputDisabled = false + buttonsDisabled = false + readonly = false + allowInput = true + keyboard = true + wheel = false + clamp = true + fullWidth = false + showButtons = true + showValidationMessage = true + + decrementLabel = "Decrease value" + incrementLabel = "Increase value" + controlsLabel = "Quantity controls" + requiredMessage = "A value is required." + minMessage = "Value is below the minimum." + maxMessage = "Value is above the maximum." + + @event input = function + @event change = function + @event increment = function + @event decrement = function + } + + state currentValue = value + state committedValue = value + + functions { + function inputId() { + if (id !== "") { + return id + } + + if (name !== "") { + return name + } + + return "input-number" + } + + function descriptionId() { + return inputId() + "-description" + } + + function messageId() { + return inputId() + "-message" + } + + function componentColor() { + if (color === "secondary") { + return "var(--wire-color-secondary)" + } + + if (color === "success") { + return "var(--wire-color-success)" + } + + if (color === "warning") { + return "var(--wire-color-warning)" + } + + if (color === "danger") { + return "var(--wire-color-danger)" + } + + if (color === "info") { + return "var(--wire-color-info)" + } + + return "var(--wire-color-primary)" + } + + function hasMin() { + return min !== "" && min !== null && min !== undefined + } + + function hasMax() { + return max !== "" && max !== null && max !== undefined + } + + function isBlank() { + return currentValue === "" || currentValue === null || currentValue === undefined + } + + function normalizedStep() { + return Number(step) > 0 ? Number(step) : 1 + } + + function inferredPrecision() { + if (precision !== "auto" && precision !== "") { + return Math.max(0, Number(precision) || 0) + } + + if (String(normalizedStep()).includes(".")) { + return String(normalizedStep()).split(".")[1].length + } + + return 0 + } + + function precisionFactor() { + return Math.pow(10, inferredPrecision()) + } + + function roundValue(nextValue) { + return Math.round(Number(nextValue) * precisionFactor()) / precisionFactor() + } + + function clampValue(nextValue) { + nextValue = Number(nextValue) + + if (hasMin() && nextValue < Number(min)) { + nextValue = Number(min) + } + + if (hasMax() && nextValue > Number(max)) { + nextValue = Number(max) + } + + return roundValue(nextValue) + } + + function isBelowMin() { + return !isBlank() && hasMin() && Number(currentValue) < Number(min) + } + + function isAboveMax() { + return !isBlank() && hasMax() && Number(currentValue) > Number(max) + } + + function isInvalid() { + return ( + invalid || + error !== "" || + (required && isBlank()) || + isBelowMin() || + isAboveMax() + ) + } + + function validationMessage() { + if (error !== "") { + return error + } + + if (required && isBlank()) { + return requiredMessage + } + + if (isBelowMin()) { + return minMessage + } + + if (isAboveMax()) { + return maxMessage + } + + return "" + } + + function hasMessage() { + return ( + helpText !== "" || + (showValidationMessage && isInvalid() && validationMessage() !== "") + ) + } + + function describedBy() { + if (description !== "" && hasMessage()) { + return descriptionId() + " " + messageId() + } + + if (description !== "") { + return descriptionId() + } + + if (hasMessage()) { + return messageId() + } + + return "" + } + + function decrementDisabled() { + return ( + disabled || + readonly || + buttonsDisabled || + (hasMin() && !isBlank() && Number(currentValue) <= Number(min)) + ) + } + + function incrementDisabled() { + return ( + disabled || + readonly || + buttonsDisabled || + (hasMax() && !isBlank() && Number(currentValue) >= Number(max)) + ) + } + + function dispatchInputNumberEvent( + sourceEvent, + eventName, + action, + previousValue, + root, + customEvent + ) { + root = sourceEvent.currentTarget.closest("[data-wrn-input-number]") + + if (!root && sourceEvent.target) { + root = sourceEvent.target.closest("[data-wrn-input-number]") + } + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent(eventName, true, false, { + component: "InputNumber", + name: name, + value: currentValue, + previousValue: previousValue, + action: action, + min: hasMin() ? Number(min) : null, + max: hasMax() ? Number(max) : null, + step: normalizedStep(), + valid: !isInvalid() + }) + root.dispatchEvent(customEvent) + } + + function applyControlValue(nextValue, action, sourceEvent, previousValue) { + previousValue = currentValue + currentValue = clampValue(nextValue) + committedValue = currentValue + + dispatchInputNumberEvent( + sourceEvent, + "input", + action, + previousValue + ) + dispatchInputNumberEvent( + sourceEvent, + "change", + action, + previousValue + ) + dispatchInputNumberEvent( + sourceEvent, + action, + action, + previousValue + ) + } + + function incrementValue(sourceEvent, nextValue) { + if (incrementDisabled()) { + return + } + + if (isBlank()) { + nextValue = hasMin() ? Number(min) : normalizedStep() + } else { + nextValue = + Number(currentValue) + + normalizedStep() * (sourceEvent.shiftKey ? 10 : 1) + } + + applyControlValue(nextValue, "increment", sourceEvent) + } + + function decrementValue(sourceEvent, nextValue) { + if (decrementDisabled()) { + return + } + + if (isBlank()) { + nextValue = hasMax() ? Number(max) : -normalizedStep() + } else { + nextValue = + Number(currentValue) - + normalizedStep() * (sourceEvent.shiftKey ? 10 : 1) + } + + applyControlValue(nextValue, "decrement", sourceEvent) + } + + function handleInput(sourceEvent, previousValue, nextValue) { + sourceEvent.stopPropagation() + previousValue = currentValue + nextValue = sourceEvent.target.value + + if (nextValue === "") { + currentValue = "" + } else if (!Number.isNaN(Number(nextValue))) { + currentValue = roundValue(Number(nextValue)) + } + + dispatchInputNumberEvent( + sourceEvent, + "input", + "input", + previousValue + ) + } + + function handleChange(sourceEvent, previousValue) { + sourceEvent.stopPropagation() + previousValue = committedValue + + if (!isBlank()) { + currentValue = clamp + ? clampValue(currentValue) + : roundValue(currentValue) + } + + committedValue = currentValue + + dispatchInputNumberEvent( + sourceEvent, + "change", + "change", + previousValue + ) + } + + function handleKeydown(sourceEvent) { + if ( + !keyboard || + disabled || + readonly || + inputDisabled || + !allowInput + ) { + return + } + + if (sourceEvent.key === "ArrowUp") { + sourceEvent.preventDefault() + incrementValue(sourceEvent) + } else if (sourceEvent.key === "ArrowDown") { + sourceEvent.preventDefault() + decrementValue(sourceEvent) + } else if (sourceEvent.key === "Home" && hasMin()) { + sourceEvent.preventDefault() + applyControlValue(Number(min), "decrement", sourceEvent) + } else if (sourceEvent.key === "End" && hasMax()) { + sourceEvent.preventDefault() + applyControlValue(Number(max), "increment", sourceEvent) + } + } + + function handleWheel(sourceEvent) { + if ( + !wheel || + disabled || + readonly || + inputDisabled || + !allowInput + ) { + return + } + + sourceEvent.preventDefault() + + if (sourceEvent.deltaY < 0) { + incrementValue(sourceEvent) + } else if (sourceEvent.deltaY > 0) { + decrementValue(sourceEvent) + } + } + } + + view { +
+ {#if label !== "" && variant !== "labeled" && variant !== "seat"} + + {/if} + + {#if description !== "" && variant !== "labeled" && variant !== "seat"} +

+ {description} +

+ {/if} + +
+ {#if variant === "horizontal" && showButtons} + + {/if} + +
+ {#if variant === "labeled" || variant === "seat"} +
+ {#if label !== ""} + + {/if} + + {#if description !== ""} + + {description} + + {/if} +
+ {/if} + +
+ {#if prefix !== ""} + + {/if} + + + + {#if suffix !== ""} + + {/if} +
+
+ + {#if variant === "horizontal" && showButtons} + + {:else} + {#if showButtons} +
+ + + +
+ {/if} + {/if} +
+ + {#if showValidationMessage && isInvalid() && validationMessage() !== ""} + + {/if} + + {#if (!showValidationMessage || !isInvalid() || validationMessage() === "") && helpText !== ""} +

+ {helpText} +

+ {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Kbd.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Kbd.wrn new file mode 100644 index 00000000..e14edc4c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Kbd.wrn @@ -0,0 +1,9 @@ +component Kbd { + props { + size = "default" + color = "primary" + label = "⌘ K" + class = "" + } + view { {label} } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/LayoutSplitter.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/LayoutSplitter.wrn new file mode 100644 index 00000000..f9ad4d58 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/LayoutSplitter.wrn @@ -0,0 +1,16 @@ +component LayoutSplitter { + props { + @event resizeStart = function + @event resize = function + @event resizeEnd = function + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + view { +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/LegendIndicator.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/LegendIndicator.wrn new file mode 100644 index 00000000..1fae3791 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/LegendIndicator.wrn @@ -0,0 +1,21 @@ +component LegendIndicator { + props { + @event toggle = function + @event select = function + size = "default" + color = "primary" + title = "Legend Indicator" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Link.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Link.wrn new file mode 100644 index 00000000..3cf17764 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Link.wrn @@ -0,0 +1,47 @@ +component Link { + props { + size = "default" + color = "primary" + label = "Link" + href = "#" + target = "" + rel = "" + external = false + class = "" + } + + view { + + {label} + + {#if external} + + {/if} + + + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/List.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/List.wrn new file mode 100644 index 00000000..0ac667a7 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/List.wrn @@ -0,0 +1,107 @@ +component List { + props { + size = "default" + color = "primary" + title = "List" + description = "" + items = [] + variant = "default" + class = "" + } + + view { +
+ {#if title || description} +
+ {#if title} +

{title}

+ {/if} + {#if description} +

{description}

+ {/if} +
+ {/if} + + + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ListGroup.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ListGroup.wrn new file mode 100644 index 00000000..35366c9c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ListGroup.wrn @@ -0,0 +1,21 @@ +component ListGroup { + props { + @event select = function + @event change = function + size = "default" + color = "primary" + title = "List Group" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Map.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Map.wrn new file mode 100644 index 00000000..6d0da585 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Map.wrn @@ -0,0 +1,85 @@ +component Map { + props { + size = "default" + color = "primary" + title = "Map" + description = "" + items = [] + variant = "default" + class = "" + } + + view { +
+ {#if title || description} +
+
+ {#if title} +

{title}

+ {/if} + {#if description} +

{description}

+ {/if} +
+ + + +
+ {/if} + +
+ + +
+ +
+ + {#if items.length > 0} + {#each items as item, index} + + {/each} + {/if} + +
+ + +
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/MarketingSectionHeader.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/MarketingSectionHeader.wrn new file mode 100644 index 00000000..5d3d9de3 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/MarketingSectionHeader.wrn @@ -0,0 +1,59 @@ +component MarketingSectionHeader { + props { + id = "" + eyebrow = "" + title = "" + description = "" + align = "split" + size = "default" + color = "primary" + actionLabel = "" + actionHref = "" + actionIcon = "" + actionExternal = false + class = "" + } + + view { +
+ +
+ +
+ +
+ {#if actionLabel} + + {/if} + +
+ + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Marquee.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Marquee.wrn new file mode 100644 index 00000000..53d4ca7b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Marquee.wrn @@ -0,0 +1,111 @@ +component Marquee { + props { + size = "default" + color = "primary" + title = "Marquee" + description = "" + items = [] + variant = "default" + class = "" + } + + state paused = false + + view { +
+
+ {#if title} +
+ + {title} +
+ {/if} + +
+
+ {#each items as item} + + + {item.label || item.title} + {#if item.meta} + {item.meta} + {/if} + + {:empty} +

{description || "No announcements available."}

+ {/each} + + {#if items.length > 0} + {#each items as item} + + {/each} + {/if} +
+
+ + +
+ + +
+ } + + style { + .wire-marquee-track { + animation: wire-marquee 32s linear infinite; + } + + .wire-marquee-paused { + animation-play-state: paused; + } + + @keyframes wire-marquee { + from { transform: translateX(0); } + to { transform: translateX(-50%); } + } + + @media (prefers-reduced-motion: reduce) { + .wire-marquee-track { + animation: none; + } + } + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/MegaMenu.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/MegaMenu.wrn new file mode 100644 index 00000000..303025b0 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/MegaMenu.wrn @@ -0,0 +1,20 @@ +component MegaMenu { + props { + @event open = function + @event close = function + @event select = function + size = "default" + color = "primary" + label = "Mega Menu" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/MetricCard.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/MetricCard.wrn new file mode 100644 index 00000000..efc63fc4 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/MetricCard.wrn @@ -0,0 +1,107 @@ +component MetricCard { + props { + label = "Metric" + value = "0" + description = "" + icon = "" + prefix = "" + suffix = "" + trend = "" + trendLabel = "" + trendDirection = "neutral" + href = "" + actionLabel = "" + size = "default" + color = "primary" + variant = "default" + align = "left" + class = "" + } + + view { +
+
+
+

{label}

+

+ {prefix}{value}{suffix} +

+
+ + {#if icon} + + + + {/if} +
+ + {#if description} +

{description}

+ {/if} + + {#if trend || trendLabel} +
+ + {#if trendDirection === "up" || trendDirection === "positive"} + + {:else if trendDirection === "down" || trendDirection === "negative"} + + {:else} + + {/if} + {trend} + + {#if trendLabel} + {trendLabel} + {/if} +
+ {/if} + + {#if href} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/MetricGrid.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/MetricGrid.wrn new file mode 100644 index 00000000..5e353cff --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/MetricGrid.wrn @@ -0,0 +1,60 @@ +component MetricGrid { + props { + items = [] + columns = 4 + tabletColumns = 2 + mobileColumns = 1 + gap = "md" + equalHeight = true + dividers = false + size = "default" + color = "primary" + variant = "default" + class = "" + } + + view { +
+ {#each items as item} + + {:empty} + + {/each} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Modal.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Modal.wrn new file mode 100644 index 00000000..2366e70f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Modal.wrn @@ -0,0 +1,23 @@ +component Modal { + props { + @event open = function + @event close = function + @event cancel = function + @event confirm = function + size = "default" + color = "primary" + title = "Modal" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Nav.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Nav.wrn new file mode 100644 index 00000000..de980dc7 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Nav.wrn @@ -0,0 +1,19 @@ +component Nav { + props { + @event select = function + @event change = function + size = "default" + color = "primary" + label = "Nav" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Navbar.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Navbar.wrn new file mode 100644 index 00000000..b6f85083 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Navbar.wrn @@ -0,0 +1,140 @@ +component Navbar { + props { + @event toggle = function + @event open = function + @event close = function + @event select = function + @event action = function + size = "default" + color = "primary" + label = "Primary navigation" + topbarLabel = "Utility navigation" + brand = {} + items = [] + actions = [] + active = "" + sticky = false + openOnHover = false + maxWidth = "full" + mobileLabel = "Toggle navigation" + class = "" + } + + state mobileOpen = false + + functions { + function toggleNavigation() { + mobileOpen = !mobileOpen + $emit("toggle", { open: mobileOpen }) + $emit(mobileOpen ? "open" : "close", { source: "mobile" }) + } + + function selectItem(item, level) { + mobileOpen = false + $emit("select", { item: item, value: item.value || "", level: level }) + } + + function selectAction(item) { + mobileOpen = false + $emit("action", { item: item, value: item.value || "" }) + } + + function isItemActive(item) { + if (!item) return false + if (item.value && item.value === active) return true + if (!item.children || !item.children.length) return false + return item.children.some(function (child) { + return isItemActive(child) + }) + } + + function toggleDropdown(event, item) { + $emit(event.currentTarget.open ? "open" : "close", { + source: "menu", + item: item + }) + } + } + + view { +
+
+ +
+ +
+ + {#if brand.logo} + + {/if} + {#if brand.icon} + + {/if} + {#if brand.label || brand.description} + + {#if brand.label}{brand.label}{/if} + {#if brand.description}{brand.description}{/if} + + {/if} + + + + +
+ + +
+ {#each actions as item} + + {#if item.icon}{/if} + {item.label} + + {/each} + +
+
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PageHeader.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PageHeader.wrn new file mode 100644 index 00000000..42132045 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PageHeader.wrn @@ -0,0 +1,105 @@ +component PageHeader { + props { + eyebrow = "" + title = "" + description = "" + icon = "" + align = "left" + size = "default" + compact = false + showBreadcrumbs = false + breadcrumbs = [] + primaryLabel = "" + primaryHref = "" + primaryIcon = "" + secondaryLabel = "" + secondaryHref = "" + secondaryIcon = "" + color = "primary" + variant = "default" + class = "" + } + + view { +
+
+ {#if showBreadcrumbs && breadcrumbs.length > 0} + + {/if} + +
+
+ {#if icon} + + + + {/if} + + + + +
+ +
+ {#if secondaryLabel} +
+
+ + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Pagination.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Pagination.wrn new file mode 100644 index 00000000..afbfc65c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Pagination.wrn @@ -0,0 +1,20 @@ +component Pagination { + props { + @event change = function + @event previous = function + @event next = function + size = "default" + color = "primary" + label = "Pagination" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PinInput.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PinInput.wrn new file mode 100644 index 00000000..8aa45c9e --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PinInput.wrn @@ -0,0 +1,114 @@ +component PinInput { + props { + size = "default" + color = "primary" + label = "Verification code" + name = "pin" + value = "" + length = 4 + pattern = "[0-9]" + type = "text" + inputMode = "numeric" + placeholder = "○" + autocomplete = "one-time-code" + masked = false + disabled = false + readonly = false + required = false + autoFocus = false + autoSubmit = false + allowPaste = true + clearable = true + clearLabel = "Clear code" + separator = "" + groupSize = 0 + helpText = "" + invalid = false + validationMessage = "" + class = "" + @event input = function + @event change = function + @event complete = function + @event paste = function + @event clear = function + @event error = function + } + + functions { + function inputIndexes() { + return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].slice( + 0, + Math.max(1, Math.min(12, Number(length))) + ) + } + } + + view { +
+
+ {label} + +
+ +
+ {#each inputIndexes() as index} + + {#if separator && groupSize !== 0 && (index + 1) % groupSize === 0 && index + 1 !== length} + + {/if} + {/each} +
+ + + + {#if helpText && !validationMessage}{helpText}{/if} + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Popover.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Popover.wrn new file mode 100644 index 00000000..2b196a00 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Popover.wrn @@ -0,0 +1,21 @@ +component Popover { + props { + @event open = function + @event close = function + size = "default" + color = "primary" + title = "Popover" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { +
+
{title}
+ {#if description}

{description}

{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PortalDashboard.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PortalDashboard.wrn new file mode 100644 index 00000000..e8001518 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PortalDashboard.wrn @@ -0,0 +1,98 @@ +component PortalDashboard { + props { + @event action = function + @event navigate = function + size = "default" + color = "primary" + eyebrow = "Overview" + eyebrowKey = "" + title = "Dashboard" + titleKey = "" + description = "" + descriptionKey = "" + userName = "" + metrics = [] + actions = [] + updates = [] + tasks = [] + class = "" + } + + functions { + function chooseAction(item, index) { + $emit("action", { item: item, value: item.value || "", index: index }) + } + + function chooseNavigation(item, index) { + $emit("navigate", { item: item, value: item.value || "", index: index }) + } + } + + view { +
+
+
+ {#if eyebrowKey}{eyebrow}{/if} + {#if !eyebrowKey}{eyebrow}{/if} +

+ {#if titleKey}{title}{/if} + {#if !titleKey}{title}{/if} + {#if userName}, {userName}{/if} +

+ {#if descriptionKey}

{description}

{/if} + {#if !descriptionKey && description}

{description}

{/if} +
+
+
+ +
+ {#each metrics as item} +
+ +
{item.label}{item.value}{#if item.detail}{item.detail}{/if}
+
+ {/each} +
+ +
+
+
Shortcuts

Quick actions

+
+ {#each actions as item, index} + + + {item.label}{#if item.description}{item.description}{/if} + + + {/each} +
+
+ +
+
Priority

Tasks requiring attention

+ +
+ +
+
Latest

Recent updates

+
+ {#each updates as item} +
+ +
{item.label}{#if item.detail}

{item.detail}

{/if}{item.time || ''}
+
+ {/each} +
+
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PreferenceSwitcher.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PreferenceSwitcher.wrn new file mode 100644 index 00000000..29962022 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PreferenceSwitcher.wrn @@ -0,0 +1,82 @@ +component PreferenceSwitcher { + props { + @event theme = function + @event color = function + @event language = function + size = "default" + color = "primary" + themeLabel = "Theme" + colorLabel = "Accent color" + languageLabel = "Language" + languages = [ + {"label": "English", "shortLabel": "EN", "value": "en"}, + {"label": "हिन्दी", "shortLabel": "हि", "value": "hi"}, + {"label": "मराठी", "shortLabel": "म", "value": "mr"} + ] + colors = [ + {"label": "Blue", "value": "blue", "hex": "#2563eb"}, + {"label": "Cyan", "value": "cyan", "hex": "#0891b2"}, + {"label": "Emerald", "value": "emerald", "hex": "#059669"}, + {"label": "Violet", "value": "violet", "hex": "#7c3aed"}, + {"label": "Rose", "value": "rose", "hex": "#e11d48"}, + {"label": "Amber", "value": "amber", "hex": "#d97706"} + ] + compact = true + class = "" + } + + functions { + function choose(type, value) { + $emit(type, { value: value }) + } + } + + view { +
+
+ + + {#if !compact}{themeLabel}{/if} + +
+ {themeLabel} +
+ + +
+
+
+ +
+ + + {#if !compact}{colorLabel}{/if} + +
+ {colorLabel} +
+ {#each colors as item} + + {/each} +
+
+
+ +
+ + + + {#if !compact}{languageLabel}{/if} + +
+ {languageLabel} + {#each languages as item} + + {/each} +
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PublicPageShell.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PublicPageShell.wrn new file mode 100644 index 00000000..e98f9c02 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/PublicPageShell.wrn @@ -0,0 +1,53 @@ +component PublicPageShell { + props { + maxWidth = "full" + fullWidth = true + headerOffset = "none" + background = "default" + overflow = "clip" + minHeight = "screen" + size = "default" + color = "primary" + variant = "default" + class = "" + } + + view { +
+ + + {#if fullWidth} +
+ +
+ {:else} +
+ +
+ {/if} + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Radio.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Radio.wrn new file mode 100644 index 00000000..1da0c2a8 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Radio.wrn @@ -0,0 +1,56 @@ +component Radio { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Radio" + hiddenLabel = false + placeholder = "" + variant = "normal" + icon = "" + iconPosition = "start" + value = "on" + options = [] + checked = false + orientation = "vertical" + card = false + rightAligned = false + list = false + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { checked: sourceEvent.currentTarget.checked, value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
{#if options.length || cornerHint}{label}{#if cornerHint}{cornerHint}{/if}{/if}
+ {#if options.length} +
+ {#each options as option} + + {/each} +
+ {:else} + + {/if} + {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/RangeSlider.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/RangeSlider.wrn new file mode 100644 index 00000000..f501e7bb --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/RangeSlider.wrn @@ -0,0 +1,68 @@ +component RangeSlider { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Range" + hiddenLabel = false + placeholder = "" + variant = "normal" + icon = "" + iconPosition = "start" + value = 50 + min = 0 + max = 100 + step = 1 + showValue = true + showBounds = true + showSteps = false + marks = [] + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + state currentValue = value + functions { + function percent() { if (Number(max) === Number(min)) { return 0 } return (Number(currentValue) - Number(min)) / (Number(max) - Number(min)) * 100 } + function setValue(nextValue, sourceEvent, commit, detail, root, slider, input, output, progressValue) { if (readonly || disabled) { return } currentValue = Number(nextValue); root = sourceEvent.currentTarget.closest(".wire-next--range-slider"); if (root) { slider = root.querySelector("[role=slider]"); input = root.querySelector("input[name='" + name + "']"); output = root.querySelector("output"); progressValue = (currentValue - Number(min)) / (Number(max) - Number(min)) * 100; if (slider) { slider.setAttribute("aria-valuenow", String(currentValue)); slider.style.setProperty("--wire-range-progress", progressValue + "%") } if (input) { input.value = String(currentValue) } if (output) { output.textContent = String(currentValue) } } detail = { value: currentValue, min: min, max: max, step: step, name: name, sourceEvent: sourceEvent }; $emit("input", detail); if (commit) { $emit("change", detail) } } + function valueFromPointer(sourceEvent, rect, ratio) { rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); return Number(min) + ratio * (Number(max) - Number(min)) } + function beginSlide(sourceEvent, rect, ratio, rawValue) { if (readonly || disabled) { return } sourceEvent.currentTarget.setPointerCapture(sourceEvent.pointerId); rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function moveSlide(sourceEvent, rect, ratio, rawValue) { if (!sourceEvent.currentTarget.hasPointerCapture(sourceEvent.pointerId)) { return } rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function endSlide(sourceEvent, rect, ratio, rawValue) { rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); if (sourceEvent.currentTarget.hasPointerCapture(sourceEvent.pointerId)) { sourceEvent.currentTarget.releasePointerCapture(sourceEvent.pointerId) } $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function selectMark(sourceEvent, root, slider, input, output, nextValue, progressValue, detail) { if (readonly || disabled) { return } root = sourceEvent.currentTarget.closest(".wire-next--range-slider"); slider = root.querySelector(".wire-next__custom-slider"); input = root.querySelector(".wire-next__range-value"); output = root.querySelector("output"); nextValue = Number(sourceEvent.currentTarget.dataset.value); currentValue = nextValue; progressValue = (nextValue - Number(min)) / (Number(max) - Number(min)) * 100; slider.setAttribute("aria-valuenow", String(nextValue)); slider.style.setProperty("--wire-range-progress", progressValue + "%"); input.setAttribute("value", String(nextValue)); output.replaceChildren(String(nextValue)); detail = { value: nextValue, min: min, max: max, step: step, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function handleKey(sourceEvent) { if (sourceEvent.key === "ArrowRight") { sourceEvent.preventDefault(); currentValue = Math.min(Number(max), Number(currentValue) + Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "ArrowLeft") { sourceEvent.preventDefault(); currentValue = Math.max(Number(min), Number(currentValue) - Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "Home") { sourceEvent.preventDefault(); currentValue = Number(min); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "End") { sourceEvent.preventDefault(); currentValue = Number(max); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } } + function emitFocus(nameEvent, sourceEvent) { $emit(nameEvent, { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function decreaseValue(sourceEvent) { currentValue = Math.max(Number(min), Number(currentValue) - Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function increaseValue(sourceEvent) { currentValue = Math.min(Number(max), Number(currentValue) + Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if icon}{/if} + +
+ +
+ + {#if marks.length}{#each marks as mark}{/each}{/if} +
+ {#if showBounds}
{min}Step {step}{max}
{/if} +
+ {#if showValue}{currentValue}{/if} + +
+ {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Rating.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Rating.wrn new file mode 100644 index 00000000..a92de2af --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Rating.wrn @@ -0,0 +1,21 @@ +component Rating { + props { + @event input = function + @event change = function + size = "default" + color = "primary" + title = "Rating" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Scrollspy.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Scrollspy.wrn new file mode 100644 index 00000000..305d2d72 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Scrollspy.wrn @@ -0,0 +1,18 @@ +component Scrollspy { + props { + @event change = function + size = "default" + color = "primary" + label = "Scrollspy" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/SearchBox.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/SearchBox.wrn new file mode 100644 index 00000000..bcb7243a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/SearchBox.wrn @@ -0,0 +1,80 @@ +component SearchBox { + props { + size = "default" + color = "primary" + label = "Search Box" + name = "" + value = "" + placeholder = "" + type = "search" + min = "" + max = "" + step = "" + disabled = false + required = false + class = "" + } + + state query = value + + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Section.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Section.wrn new file mode 100644 index 00000000..c0e65c22 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Section.wrn @@ -0,0 +1,60 @@ +component Section { + props { + id = "" + size = "default" + color = "primary" + variant = "default" + spacing = "lg" + maxWidth = "xl" + fullWidth = false + borderTop = false + borderBottom = false + class = "" + } + + view { +
+ {#if fullWidth} + + {:else} + + + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/SectionHeader.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/SectionHeader.wrn new file mode 100644 index 00000000..a70c54fb --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/SectionHeader.wrn @@ -0,0 +1,113 @@ +component SectionHeader { + props { + id = "" + eyebrow = "" + title = "" + description = "" + align = "left" + size = "default" + color = "primary" + headingLevel = 2 + maxWidth = "3xl" + class = "" + } + + view { +
+
+
+ + + {#if eyebrow} +

+ {eyebrow} +

+ {/if} +
+ + {#if headingLevel === 1} +

+ {title} +

+ {:else if headingLevel === 3} +

+ {title} +

+ {:else} +

+ {title} +

+ {/if} + + {#if description} +

+ {description} +

+ {/if} + + +
+ +
+ +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Select.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Select.wrn new file mode 100644 index 00000000..23c13a94 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Select.wrn @@ -0,0 +1,61 @@ +component Select { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event open = function + @event close = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Select" + hiddenLabel = false + value = "" + values = [] + options = [] + placeholder = "Select an option" + variant = "normal" + icon = "" + iconPosition = "start" + helperText = "" + cornerHint = "" + error = "" + inline = false + multiple = false + readonly = false + disabled = false + required = false + class = "" + } + functions { + function selected(option) { + if (multiple) return values.includes(option.value) + return option.value === value + } + function emitField(nameEvent, sourceEvent) { + sourceEvent.stopPropagation() + $emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) + } + function handleFocus(sourceEvent) { emitField("focus", sourceEvent); $emit("open", { name: name, sourceEvent: sourceEvent }) } + function handleBlur(sourceEvent) { emitField("blur", sourceEvent); $emit("close", { name: name, sourceEvent: sourceEvent }) } + function handleInvalid(sourceEvent) { $emit("invalid", { name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if icon}{/if} + + {#if variant === "floating"}{label}{/if} +
+ {#if helperText}{helperText}{/if} + {error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Sidebar.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Sidebar.wrn new file mode 100644 index 00000000..7e64904a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Sidebar.wrn @@ -0,0 +1,79 @@ +component Sidebar { + props { + @event toggle = function + @event open = function + @event close = function + @event select = function + size = "default" + color = "primary" + label = "Sidebar" + items = [] + active = "" + orientation = "horizontal" + mobileLabel = "Open navigation" + class = "" + } + + state mobileOpen = false + + functions { + function toggleSidebar() { + mobileOpen = !mobileOpen + $emit("toggle", { open: mobileOpen }) + $emit(mobileOpen ? "open" : "close", { source: "mobile" }) + } + + function closeSidebar() { + mobileOpen = false + $emit("close", { source: "mobile" }) + } + + function selectItem(item, level) { + mobileOpen = false + $emit("select", { item: item, value: item.value || "", level: level }) + } + } + + view { +
+ + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/SplitHero.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/SplitHero.wrn new file mode 100644 index 00000000..cd523eb1 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/SplitHero.wrn @@ -0,0 +1,98 @@ +component SplitHero { + props { + eyebrow = "" + title = "A better digital experience" + highlight = "" + description = "" + primaryLabel = "" + primaryHref = "" + primaryIcon = "" + secondaryLabel = "" + secondaryHref = "" + secondaryIcon = "" + visualPosition = "right" + reverse = false + ratio = "balanced" + size = "default" + color = "primary" + variant = "default" + trustItems = [] + class = "" + } + + view { +
+
+
+ {#if eyebrow} +
+ + {eyebrow} +
+ {/if} + +

+ {title} + {#if highlight} + {highlight} + {/if} +

+ + {#if description} +

{description}

+ {/if} + + + + + + {#if trustItems.length > 0} +
+ {#each trustItems as item} + + + {item.label || item.title || item} + + {/each} +
+ {/if} + + + +
+ +
+ + +
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/StatsBar.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/StatsBar.wrn new file mode 100644 index 00000000..46cb04e9 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/StatsBar.wrn @@ -0,0 +1,40 @@ +component StatsBar { + props { + items = [] + columns = 4 + compact = true + dividers = true + icons = true + size = "default" + color = "primary" + variant = "raised" + maxWidth = "xl" + class = "" + } + + view { +
+
+ +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Stepper.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Stepper.wrn new file mode 100644 index 00000000..725ab1c2 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Stepper.wrn @@ -0,0 +1,21 @@ +component Stepper { + props { + @event change = function + @event previous = function + @event next = function + @event complete = function + size = "default" + color = "primary" + label = "Stepper" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/StrongPassword.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/StrongPassword.wrn new file mode 100644 index 00000000..d8f3137d --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/StrongPassword.wrn @@ -0,0 +1,215 @@ +component StrongPassword { + props { + size = "default" + color = "primary" + label = "Password" + name = "password" + value = "" + placeholder = "Create a strong password" + autocomplete = "new-password" + minLength = 8 + specialCharactersSet = "!@#$%^&*()_+-=[]{}|;:,.<>?" + requireLowercase = true + requireUppercase = true + requireNumber = true + requireSpecialCharacter = true + showRequirements = true + presentation = "inline" + hintText = "Use a unique password you do not use elsewhere." + emptyLabel = "Enter a password" + weakLabel = "Weak" + fairLabel = "Fair" + goodLabel = "Good" + strongLabel = "Strong" + disabled = false + readonly = false + required = false + invalid = false + validationMessage = "" + class = "" + @event input = function + @event change = function + @event strength = function + } + + state password = value + state detailsOpen = false + + functions { + function hasMinimumLength() { + return password.length >= Number(minLength) + } + + function hasLowercase() { + return password !== password.toUpperCase() + } + + function hasUppercase() { + return password !== password.toLowerCase() + } + + function hasNumber() { + return containsCharacterAt("0123456789", 0) + } + + function hasSpecialCharacter() { + return containsCharacterAt(specialCharactersSet, 0) + } + + function containsCharacterAt(characters, index) { + if (index >= characters.length) { + return false + } + if (password.includes(characters[index])) { + return true + } + return containsCharacterAt(characters, index + 1) + } + + function score() { + return (hasMinimumLength() ? 1 : 0) + (requireLowercase && hasLowercase() ? 1 : 0) + (requireUppercase && hasUppercase() ? 1 : 0) + (requireNumber && hasNumber() ? 1 : 0) + (requireSpecialCharacter && hasSpecialCharacter() ? 1 : 0) + } + + function maximumScore() { + return 1 + (requireLowercase ? 1 : 0) + (requireUppercase ? 1 : 0) + (requireNumber ? 1 : 0) + (requireSpecialCharacter ? 1 : 0) + } + + function strengthPercent() { + return Math.round(score() / maximumScore() * 100) + } + + function strengthLevel() { + if (!password) { + return "empty" + } + if (strengthPercent() <= 25) { + return "weak" + } + if (strengthPercent() <= 50) { + return "fair" + } + if (strengthPercent() < 100) { + return "good" + } + return "strong" + } + + function strengthLabel() { + if (strengthLevel() === "weak") { + return weakLabel + } + if (strengthLevel() === "fair") { + return fairLabel + } + if (strengthLevel() === "good") { + return goodLabel + } + if (strengthLevel() === "strong") { + return strongLabel + } + return emptyLabel + } + + } + + view { +
+ +
+ + + {#if presentation === "popover"} +
+ +
+
+ Password strength + {password ? strengthLabel() : emptyLabel} +
+
+ +
+ {#if showRequirements} +
    +
  • + At least {minLength} characters +
  • + {#if requireLowercase}
  • One lowercase letter
  • {/if} + {#if requireUppercase}
  • One uppercase letter
  • {/if} + {#if requireNumber}
  • One number
  • {/if} + {#if requireSpecialCharacter}
  • One special character: {specialCharactersSet}
  • {/if} +
+ {/if} + {#if hintText}{hintText}{/if} +
+
+ {/if} +
+ + {#if presentation !== "popover"} +
+
+ Password strength + {password ? strengthLabel() : emptyLabel} +
+
+ +
+ {#if showRequirements} +
    +
  • At least {minLength} characters
  • + {#if requireLowercase}
  • One lowercase letter
  • {/if} + {#if requireUppercase}
  • One uppercase letter
  • {/if} + {#if requireNumber}
  • One number
  • {/if} + {#if requireSpecialCharacter}
  • One special character: {specialCharactersSet}
  • {/if} +
+ {/if} + {#if hintText}{hintText}{/if} +
+ {/if} + + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/StyledIcon.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/StyledIcon.wrn new file mode 100644 index 00000000..a394af25 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/StyledIcon.wrn @@ -0,0 +1,19 @@ +component StyledIcon { + props { + size = "default" + color = "primary" + title = "Styled Icon" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Switch.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Switch.wrn new file mode 100644 index 00000000..478a92fe --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Switch.wrn @@ -0,0 +1,39 @@ +component Switch { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Switch" + hiddenLabel = false + placeholder = "" + variant = "normal" + icon = "" + iconPosition = "start" + value = "on" + checked = false + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { checked: sourceEvent.currentTarget.checked, value: value, name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
{#if cornerHint}{label}{cornerHint}{/if}
+ + {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Tabs.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Tabs.wrn new file mode 100644 index 00000000..e8d747c4 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Tabs.wrn @@ -0,0 +1,90 @@ +component Tabs { + props { + size = "default" + color = "primary" + label = "Tabs" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + + state activeValue = active || (items[0] ? (items[0].value || items[0].id || "0") : "") + + view { +
+
+ {#each items as item, index} + + {/each} +
+ +
+ {#each items as item, index} +
+ {#if item.title && item.title !== item.label} +

{item.title}

+ {/if} + {#if item.description} +

{item.description}

+ {/if} + {#if item.content} +
{item.content}
+ {/if} +
+ {/each} + + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/TextLink.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/TextLink.wrn new file mode 100644 index 00000000..a490e020 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/TextLink.wrn @@ -0,0 +1,87 @@ +component TextLink { + props { + @event click = function + @event focus = function + @event blur = function + label = "Learn more" + href = "#" + target = "" + rel = "" + external = false + icon = "" + iconPosition = "start" + showArrow = true + underline = false + size = "default" + color = "primary" + variant = "default" + disabled = false + class = "" + } + + view { + + {#if disabled} + + {#if icon && iconPosition === "start"} + + {/if} + {label} + + {:else} + + {#if icon && iconPosition === "start"} + + {/if} + + {label} + + {#if icon && iconPosition === "end"} + + {/if} + + {#if external} + + {:else if showArrow} + + {/if} + + {/if} + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Textarea.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Textarea.wrn new file mode 100644 index 00000000..98cfc33f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Textarea.wrn @@ -0,0 +1,53 @@ +component Textarea { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Textarea" + hiddenLabel = false + placeholder = "" + value = "" + variant = "normal" + icon = "" + iconPosition = "start" + helperText = "" + cornerHint = "" + error = "" + inline = false + rows = 5 + resize = "vertical" + readonly = false + disabled = false + required = false + minlength = "" + maxlength = "" + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { + sourceEvent.stopPropagation() + $emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) + } + function handleInvalid(sourceEvent) { + $emit("invalid", { value: sourceEvent.currentTarget.value, name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) + } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if icon}{/if} + + {#if variant === "floating"}{label}{/if} +
+ {#if helperText}{helperText}{/if} + {error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/TimePicker.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/TimePicker.wrn new file mode 100644 index 00000000..64398d44 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/TimePicker.wrn @@ -0,0 +1,63 @@ +component TimePicker { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event open = function + @event close = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Time" + hiddenLabel = false + value = "" + placeholder = "" + variant = "normal" + icon = "icon-[lucide--clock-3]" + iconPosition = "end" + helperText = "" + cornerHint = "" + error = "" + inline = false + min = "" + max = "" + step = "" + format = "24" + minuteStep = 5 + hours = ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"] + minutes = ["00", "05", "10", "15", "20", "25", "30", "35", "40", "45", "50", "55"] + readonly = false + disabled = false + required = false + class = "" + } + state currentValue = value + state selectedHour = value ? value.split(":")[0] : "00" + state selectedMinute = value ? value.split(":")[1] : "00" + state expanded = false + functions { + function commit(part, nextValue, sourceEvent, next, detail) { if (part === "hour") { selectedHour = String(nextValue).padStart(2, "0") } if (part === "minute") { selectedMinute = String(nextValue).padStart(2, "0") } next = selectedHour + ":" + selectedMinute; if ((min && next < min) || (max && next > max)) { return } currentValue = next; detail = { value: currentValue, hour: selectedHour, minute: selectedMinute, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function selectTimePart(sourceEvent, root, input, parts, hourValue, minuteValue, next, trigger, detail) { root = sourceEvent.currentTarget.closest(".wire-next--time-picker"); input = root.querySelector(".wire-next__time-value"); parts = String(input.value || value || "00:00").split(":"); hourValue = sourceEvent.currentTarget.dataset.part === "hour" ? sourceEvent.currentTarget.dataset.value : parts[0]; minuteValue = sourceEvent.currentTarget.dataset.part === "minute" ? sourceEvent.currentTarget.dataset.value : parts[1]; next = hourValue + ":" + minuteValue; if ((min && next < min) || (max && next > max)) { return } currentValue = next; input.setAttribute("value", next); trigger = root.querySelector(".wire-next__time-trigger span"); if (trigger) { trigger.replaceChildren(next) } sourceEvent.currentTarget.setAttribute("aria-pressed", "true"); detail = { value: next, hour: hourValue, minute: minuteValue, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function openPicker(sourceEvent) { expanded = true; $emit("open", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function closePicker(sourceEvent) { expanded = false; $emit("close", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleFocus(sourceEvent) { $emit("focus", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleBlur(sourceEvent) { $emit("blur", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleInvalid(sourceEvent) { $emit("invalid", { name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if icon}{/if} + + +
+ + {#if helperText}{helperText}{/if} + {error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Timeline.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Timeline.wrn new file mode 100644 index 00000000..3d3d35dd --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Timeline.wrn @@ -0,0 +1,83 @@ +component Timeline { + props { + size = "default" + color = "primary" + title = "Timeline" + description = "" + items = [] + variant = "default" + class = "" + } + + view { +
+ {#if title || description} +
+ {#if title} +

{title}

+ {/if} + {#if description} +

{description}

+ {/if} +
+ {/if} + +
    + {#each items as item, index} +
  1. + + + + +
    +
    +
    +

    {item.title || item.label}

    + {#if item.subtitle} +

    {item.subtitle}

    + {/if} +
    + {#if item.date || item.meta} + + {/if} +
    + + {#if item.description} +

    {item.description}

    + {/if} + + {#if item.href} + + {item.actionLabel || "View details"} + + + {/if} +
    +
  2. + {:empty} +
  3. No timeline items available.
  4. + {/each} +
+ + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Toast.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Toast.wrn new file mode 100644 index 00000000..bda42b49 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Toast.wrn @@ -0,0 +1,21 @@ +component Toast { + props { + @event dismiss = function + @event action = function + size = "default" + color = "primary" + title = "Toast" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ToastNotifications.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ToastNotifications.wrn new file mode 100644 index 00000000..d49d5547 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ToastNotifications.wrn @@ -0,0 +1,23 @@ +component ToastNotifications { + props { + @event add = function + @event dismiss = function + @event clear = function + @event action = function + size = "default" + color = "primary" + title = "Toast Notifications" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ToggleCount.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ToggleCount.wrn new file mode 100644 index 00000000..0a858af9 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ToggleCount.wrn @@ -0,0 +1,237 @@ +component ToggleCount { + props { + size = "default" + color = "primary" + variant = "segmented" + class = "" + + name = "billing-cycle" + value = "monthly" + firstValue = "monthly" + firstLabel = "Monthly" + secondValue = "annual" + secondLabel = "Annual" + ariaLabel = "Billing frequency" + + items = [] + currency = "$" + suffix = "" + firstValueKey = "monthly" + secondValueKey = "annual" + emptyValue = "—" + + align = "end" + fullWidth = true + disabled = false + animate = true + animationDuration = 450 + animationSteps = 18 + + @event change = function + @event toggle = function + } + + state selectedValue = value + + functions { + function isFirstSelected() { + return selectedValue === firstValue + } + + function isSecondSelected() { + return selectedValue === secondValue + } + + function displayValue(item) { + if (isSecondSelected()) { + return item[secondValueKey] !== undefined + ? item[secondValueKey] + : emptyValue + } + + return item[firstValueKey] !== undefined + ? item[firstValueKey] + : emptyValue + } + + function dispatchToggleEvent(sourceEvent, previousValue, root, customEvent) { + root = sourceEvent.currentTarget.closest("[data-wrn-toggle-count]") + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("change", true, false, { + component: "ToggleCount", + name: name, + value: selectedValue, + previousValue: previousValue, + firstValue: firstValue, + secondValue: secondValue + }) + root.dispatchEvent(customEvent) + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("toggle", true, false, { + component: "ToggleCount", + name: name, + value: selectedValue, + previousValue: previousValue, + firstValue: firstValue, + secondValue: secondValue + }) + root.dispatchEvent(customEvent) + } + + function selectValue(sourceEvent, nextValue, previousValue) { + if (disabled || selectedValue === nextValue) { + return + } + + previousValue = selectedValue + selectedValue = nextValue + + if ( + animate && + !window.matchMedia("(prefers-reduced-motion: reduce)").matches + ) { + animateDisplayedValues(sourceEvent, previousValue) + } + + dispatchToggleEvent(sourceEvent, previousValue) + } + + function animateDisplayedValues(sourceEvent, previousValue, root, nodes) { + root = sourceEvent.currentTarget.closest("[data-wrn-toggle-count]") + + if (!root) { + return + } + + nodes = root.querySelectorAll("[data-toggle-count-value]") + animateValueAt(nodes, 0, previousValue) + } + + function animateValueAt(nodes, index, previousValue, node, fromValue, toValue) { + if (index >= nodes.length) { + return + } + + node = nodes[index] + fromValue = Number( + previousValue === secondValue + ? node.getAttribute("data-second-value") + : node.getAttribute("data-first-value") + ) + toValue = Number( + selectedValue === secondValue + ? node.getAttribute("data-second-value") + : node.getAttribute("data-first-value") + ) + + if (!Number.isNaN(fromValue) && !Number.isNaN(toValue)) { + animateValueFrame(node, fromValue, toValue, 0) + } + + animateValueAt(nodes, index + 1, previousValue) + } + + function animateValueFrame(node, fromValue, toValue, frame, totalFrames, nextValue) { + totalFrames = Math.max(1, Number(animationSteps) || 1) + + if (frame >= totalFrames) { + node.replaceChildren(String(toValue)) + return + } + + nextValue = Math.round( + fromValue + + (toValue - fromValue) * (frame / totalFrames) + ) + node.replaceChildren(String(nextValue)) + + setTimeout( + animateValueFrame, + Math.max(1, Number(animationDuration) / totalFrames), + node, + fromValue, + toValue, + frame + 1 + ) + } + + function toggleValue(sourceEvent) { + selectValue( + sourceEvent, + isFirstSelected() ? secondValue : firstValue + ) + } + } + + view { +
+ + +
+ {#if variant === "switch"} + {firstLabel} + + {secondLabel} + {:else} +
+ + +
+ {/if} +
+ + {#if items.length > 0} +
+ {#each items as item} +
+ {item.label || item.name} + + {#if currency}{currency}{/if} + {displayValue(item)} + {#if suffix}{suffix}{/if} + + {#if item.description}{item.description}{/if} +
+ {/each} +
+ {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/TogglePassword.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/TogglePassword.wrn new file mode 100644 index 00000000..43eb9cc6 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/TogglePassword.wrn @@ -0,0 +1,153 @@ +component TogglePassword { + props { + size = "default" + color = "primary" + label = "Password" + name = "password" + value = "" + placeholder = "Enter your password" + autocomplete = "current-password" + minlength = "" + maxlength = "" + pattern = "(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}" + fields = [] + visible = false + toggleable = true + toggleMode = "button" + checkboxLabel = "Show password" + showLabel = "Show password" + hideLabel = "Hide password" + disabled = false + readonly = false + required = false + invalid = false + helpText = "" + validationMessage = "" + class = "" + @event input = function + @event change = function + @event toggle = function + } + + state revealed = visible + + functions { + function toggleVisibility() { + if (disabled || readonly || !toggleable) { + return + } + revealed = !revealed + } + + function fieldId(field, index) { + return field.id || field.name || name + "-" + index + } + + function fieldName(field, index) { + return field.name || name + "-" + index + } + } + + view { +
+ {#if fields.length} +
+ {#each fields as field, index} +
+ +
+ + {#if toggleable && toggleMode === "button"} + + {/if} +
+
+ {/each} +
+ {:else} + +
+ + {#if toggleable && toggleMode === "button"} + + {/if} +
+ {/if} + {#if toggleable && toggleMode === "checkbox"} + + {/if} + {#if helpText && !validationMessage}{helpText}{/if} + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/TreeView.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/TreeView.wrn new file mode 100644 index 00000000..d04a730b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/TreeView.wrn @@ -0,0 +1,23 @@ +component TreeView { + props { + @event select = function + @event toggle = function + @event expand = function + @event collapse = function + size = "default" + color = "primary" + title = "Tree View" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Typography.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Typography.wrn new file mode 100644 index 00000000..d7d36173 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/Typography.wrn @@ -0,0 +1,75 @@ +component Typography { + props { + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + + view { +
+ +
+ } + + style { + .wire-typography :where(h1, h2, h3, h4) { + color: var(--wire-color-text); + font-weight: 700; + letter-spacing: -0.02em; + line-height: 1.2; + break-after: avoid; + } + + .wire-typography :where(h1) { font-size: clamp(2rem, 4vw, 3.5rem); margin: 0 0 1.5rem; } + .wire-typography :where(h2) { font-size: clamp(1.5rem, 3vw, 2.25rem); margin: 2.5rem 0 1rem; } + .wire-typography :where(h3) { font-size: 1.35rem; margin: 2rem 0 0.75rem; } + .wire-typography :where(p, ul, ol, blockquote, pre, table) { margin: 1rem 0; } + .wire-typography :where(p, li) { color: var(--wire-color-text-muted); line-height: 1.8; } + .wire-typography :where(a) { color: var(--wire-color-primary); font-weight: 600; text-underline-offset: 0.2em; } + .wire-typography :where(a:hover) { color: var(--wire-color-primary-hover); text-decoration: underline; } + .wire-typography :where(ul, ol) { padding-left: 1.4rem; } + .wire-typography :where(ul) { list-style: disc; } + .wire-typography :where(ol) { list-style: decimal; } + .wire-typography :where(blockquote) { + border-left: 4px solid var(--wire-color-primary); + background: var(--wire-color-primary-soft); + border-radius: 0 0.75rem 0.75rem 0; + padding: 1rem 1.25rem; + color: var(--wire-color-text); + } + .wire-typography :where(code) { + border-radius: 0.35rem; + background: var(--wire-color-surface-soft); + padding: 0.15rem 0.35rem; + font-size: 0.9em; + } + .wire-typography :where(pre) { + overflow-x: auto; + border: 1px solid var(--wire-color-border); + border-radius: 1rem; + background: var(--wire-color-surface-raised); + padding: 1rem; + } + .wire-typography :where(img) { border-radius: 1rem; } + .wire-typography :where(hr) { border-color: var(--wire-color-border); margin: 2rem 0; } + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/WysiwygEditor.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/WysiwygEditor.wrn new file mode 100644 index 00000000..dfb91935 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/WysiwygEditor.wrn @@ -0,0 +1,23 @@ +component WysiwygEditor { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + title = "Wysiwyg Editor" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/alert.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/alert.wrn new file mode 100644 index 00000000..ba2e904b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/alert.wrn @@ -0,0 +1,142 @@ +component Alert { + props { + size = "default" + color = "info" + variant = "soft" + class = "" + radius = "md" + shadow = "sm" + + title = "Alert" + description = "" + items = [] + actions = [] + + showIcon = false + icon = "" + dismissible = false + dismissLabel = "Dismiss alert" + role = "alert" + live = "polite" + + linkLabel = "" + linkHref = "" + actionLabel = "" + actionHref = "" + compact = false + + @event dismiss = function + @event action = function + } + + state visible = true + + functions { + function dispatchAlertEvent(sourceEvent, eventName, action, root, customEvent) { + root = sourceEvent.currentTarget.closest("[data-wrn-alert]") + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent(eventName, true, false, { + component: "Alert", + title: title, + color: color, + variant: variant, + action: action + }) + root.dispatchEvent(customEvent) + } + + function dismissAlert(sourceEvent) { + visible = false + dispatchAlertEvent(sourceEvent, "dismiss", null) + } + + function selectAction(sourceEvent, action) { + dispatchAlertEvent(sourceEvent, "action", action) + } + } + + view { +
+ {#if showIcon} + + {/if} + +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + + {#if items.length > 0} +
    + {#each items as item}
  • {item.label || item}
  • {/each} +
+ {/if} + + {#if actions.length > 0 || actionLabel || linkLabel} +
+ {#each actions as item} + {item.label} + {/each} + {#if actionLabel} + {actionLabel} + {/if} + {#if linkLabel} + {linkLabel} + {/if} +
+ {/if} +
+ + {#if dismissible} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/avatar.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/avatar.wrn new file mode 100644 index 00000000..1c90e813 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/avatar.wrn @@ -0,0 +1,87 @@ +component Avatar { + props { + @event load = function + @event error = function + @event click = function + src = "" + alt = "" + initials = "" + size = "md" + color = "primary" + variant = "solid" + shape = "circle" + + status = "" + statusLabel = "" + statusPosition = "bottom" + + badge = "" + badgeIcon = "" + badgeLabel = "" + + tooltip = "" + name = "" + description = "" + loading = "lazy" + class = "" + } + + view { + + + + {#if src} + {alt || name} + {:else if initials} + + {:else} + + {/if} + + + {#if status} + + {/if} + + {#if badgeIcon} + + + + {:else if badge} + + {badge} + + {/if} + + {#if tooltip} + {tooltip} + {/if} + + + {#if description} + + {name || alt || initials} + {description} + + {/if} + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/button.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/button.wrn new file mode 100644 index 00000000..34bf88b4 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/button.wrn @@ -0,0 +1,164 @@ +component Button { + props { + @event click = function + @event focus = function + @event blur = function + label = "Button" + loadingLabel = "Loading…" + description = "" + as = "" + href = "" + target = "" + rel = "" + type = "button" + variant = "default" + color = "primary" + size = "default" + disabled = false + loading = false + pill = false + fullWidth = false + icon = "" + iconPosition = "start" + ariaLabel = "" + ariaPressed = "" + ariaExpanded = "" + ariaControls = "" + title = "" + autofocus = false + controlClass = "" + class = "" + } + + view { + + {#if as === "a" || (as === "" && href)} + + {#if loading} + + {/if} + {#if icon && !loading && iconPosition === "start"} + + {/if} + + + {loading ? loadingLabel : label} + + {#if description && !loading} + + {description} + + {/if} + + {#if icon && !loading && iconPosition === "end"} + + {/if} + {#if (size === "icon" || size === "icon-xs" || size === "icon-sm" || size === "icon-lg") && (ariaLabel || label)} + + {/if} + + {:else} + + {/if} + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/carousel.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/carousel.wrn new file mode 100644 index 00000000..4efdb206 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/carousel.wrn @@ -0,0 +1,461 @@ +// Interactive, hydration-safe content carousel. +component Carousel { + props { + @event initialize = function + @event change = function + @event previous = function + @event next = function + @event play = function + @event pause = function + @event reachStart = function + @event reachEnd = function + @event dragStart = function + @event dragEnd = function + size = "default" + color = "primary" + title = "" + description = "" + items = [] + activeIndex = 0 + slidesPerView = 1 + gap = "0.75rem" + showPagination = false + isAutoPlay = false + autoplayInterval = 4000 + isInfiniteLoop = false + isRTL = false + isCentered = false + isDraggable = false + isAutoHeight = false + isSnap = false + showCounter = false + thumbnails = "none" + ariaLabel = "Content carousel" + variant = "default" + class = "" + } + + state currentIndex = activeIndex + state playing = false + state dragOrigin = null + state dragOffset = 0 + state autoplayTimer = null + state carouselRoot = null + + functions { + function slideCount() { + return items.length + } + + function maximumIndex(count, visible) { + count = slideCount() + visible = Math.max(1, Number(slidesPerView) || 1) + if (isCentered || isSnap) { + return Math.max(0, count - 1) + } + return Math.max(0, count - visible) + } + + function normalizedIndex(index, maximum) { + maximum = maximumIndex() + if (slideCount() === 0) { + return 0 + } + if (isInfiniteLoop) { + if (index < 0) { + return maximum + } + if (index > maximum) { + return 0 + } + } + return Math.max(0, Math.min(index, maximum)) + } + + function rememberRoot(sourceEvent, root) { + if (!sourceEvent || !sourceEvent.currentTarget) { + return + } + root = sourceEvent.currentTarget.closest(".wire-next--carousel") + if (root) { + carouselRoot = root + } + } + + function syncNavigation(sourceEvent, index, root, viewport, slides, slide, thumbnails, thumbnail, rail) { + rememberRoot(sourceEvent) + root = carouselRoot + if (!root) { + return + } + if (isSnap) { + viewport = root.querySelector(".wire-next__carousel-viewport") + slides = root.querySelectorAll(".wire-next__carousel-slide") + slide = slides[index] + if (viewport && slide) { + viewport.scrollTo({ + left: slide.offsetLeft - (viewport.clientWidth - slide.clientWidth) / 2, + behavior: "smooth" + }) + } + } + thumbnails = root.querySelectorAll(".wire-next__carousel-thumbnails button") + if (thumbnails[index]) { + thumbnail = thumbnails[index] + rail = thumbnail.parentElement + rail.scrollTo({ + left: thumbnail.offsetLeft - (rail.clientWidth - thumbnail.clientWidth) / 2, + top: thumbnail.offsetTop - (rail.clientHeight - thumbnail.clientHeight) / 2, + behavior: "smooth" + }) + } + } + + function handleSnapScroll(sourceEvent, slides, viewport, viewportCenter, closestIndex, closestDistance, slide, slideCenter, distance, previousIndex) { + if (!isSnap) { + return + } + rememberRoot(sourceEvent) + viewport = sourceEvent.currentTarget + slides = viewport.querySelectorAll(".wire-next__carousel-slide") + viewportCenter = viewport.scrollLeft + viewport.clientWidth / 2 + closestIndex = currentIndex + closestDistance = 1000000000 + slides.forEach(function (candidate, index) { + slideCenter = candidate.offsetLeft + candidate.clientWidth / 2 + distance = Math.abs(slideCenter - viewportCenter) + if (distance < closestDistance) { + closestDistance = distance + closestIndex = index + } + }) + closestIndex = normalizedIndex(closestIndex) + if (closestIndex !== currentIndex) { + previousIndex = currentIndex + currentIndex = closestIndex + $emit("change", { + index: currentIndex, + previousIndex: previousIndex, + item: items[currentIndex], + reason: "snap" + }) + slides = carouselRoot.querySelectorAll(".wire-next__carousel-thumbnails button") + slide = slides[currentIndex] + if (slide) { + viewport = slide.parentElement + viewport.scrollTo({ + left: slide.offsetLeft - (viewport.clientWidth - slide.clientWidth) / 2, + top: slide.offsetTop - (viewport.clientHeight - slide.clientHeight) / 2, + behavior: "smooth" + }) + } + } + } + + function selectSlide(index, reason, sourceEvent, previousIndex) { + if (slideCount() === 0) { + return + } + previousIndex = currentIndex + currentIndex = normalizedIndex(Number(index)) + syncNavigation(sourceEvent, currentIndex) + if (previousIndex === currentIndex && reason !== "initialize") { + return + } + $emit("change", { + index: currentIndex, + previousIndex: previousIndex, + item: items[currentIndex], + reason: reason || "select" + }) + if (currentIndex === 0) { + $emit("reachStart", { index: currentIndex }) + } + if (currentIndex === maximumIndex()) { + $emit("reachEnd", { index: currentIndex }) + } + } + + function previousSlide(sourceEvent, previousIndex) { + previousIndex = currentIndex + selectSlide(currentIndex - 1, "previous", sourceEvent) + $emit("previous", { + index: currentIndex, + previousIndex: previousIndex, + item: items[currentIndex] + }) + } + + function nextSlide(sourceEvent, previousIndex) { + previousIndex = currentIndex + selectSlide(currentIndex + 1, "next", sourceEvent) + $emit("next", { + index: currentIndex, + previousIndex: previousIndex, + item: items[currentIndex] + }) + } + + function handleKeydown(sourceEvent) { + if (sourceEvent.key === "ArrowLeft") { + sourceEvent.preventDefault() + if (isRTL) { + nextSlide(sourceEvent) + } else { + previousSlide(sourceEvent) + } + } + if (sourceEvent.key === "ArrowRight") { + sourceEvent.preventDefault() + if (isRTL) { + previousSlide(sourceEvent) + } else { + nextSlide(sourceEvent) + } + } + if (sourceEvent.key === "Home") { + sourceEvent.preventDefault() + selectSlide(0, "keyboard", sourceEvent) + } + if (sourceEvent.key === "End") { + sourceEvent.preventDefault() + selectSlide(maximumIndex(), "keyboard", sourceEvent) + } + } + + function beginDrag(sourceEvent) { + if (!isDraggable || isSnap) { + return + } + sourceEvent.preventDefault() + dragOrigin = sourceEvent.clientX + dragOffset = 0 + sourceEvent.currentTarget.setPointerCapture(sourceEvent.pointerId) + $emit("dragStart", { index: currentIndex, x: dragOrigin }) + } + + function moveDrag(sourceEvent) { + if (!isDraggable || isSnap || dragOrigin === null) { + return + } + sourceEvent.preventDefault() + dragOffset = sourceEvent.clientX - dragOrigin + } + + function cancelDrag() { + dragOrigin = null + dragOffset = 0 + } + + function endDrag(sourceEvent, distance) { + if (!isDraggable || isSnap || dragOrigin === null) { + return + } + sourceEvent.preventDefault() + distance = dragOffset || sourceEvent.clientX - dragOrigin + dragOrigin = null + dragOffset = 0 + if (Math.abs(distance) > 20) { + if ((distance < 0 && !isRTL) || (distance > 0 && isRTL)) { + nextSlide(sourceEvent) + } else { + previousSlide(sourceEvent) + } + } + $emit("dragEnd", { + index: currentIndex, + distance: distance + }) + } + + function advanceAutoplay() { + if (currentIndex >= maximumIndex()) { + selectSlide(0, "autoplay") + } else { + selectSlide(currentIndex + 1, "autoplay") + } + } + + function startAutoplay() { + if (!isAutoPlay || playing || slideCount() < 2) { + return + } + playing = true + autoplayTimer = setInterval(advanceAutoplay, Math.max(1000, Number(autoplayInterval))) + $emit("play", { index: currentIndex, interval: autoplayInterval }) + } + + function pauseAutoplay() { + if (autoplayTimer) { + clearInterval(autoplayTimer) + } + autoplayTimer = null + if (playing) { + $emit("pause", { index: currentIndex }) + } + playing = false + } + + } + + lifecycle { + mount { + $emit("initialize", { index: currentIndex, count: slideCount() }) + startAutoplay() + } + unmount { + if (autoplayTimer) { + clearInterval(autoplayTimer) + } + } + } + + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/component-catalog.json b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/component-catalog.json new file mode 100644 index 00000000..299cb70b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/component-catalog.json @@ -0,0 +1,549 @@ +{ + "sourceDocuments": ["Screenshot-directed WRNexus UI catalog reset"], + "components": [ + { + "name": "Accordion", + "category": "base", + "purpose": "Theme-aware, responsive accordion component." + }, + { + "name": "AdvancedDatePicker", + "category": "integrations", + "purpose": "Theme-aware, responsive advanced date picker component." + }, + { + "name": "AdvancedRangeSlider", + "category": "integrations", + "purpose": "Theme-aware, responsive advanced range slider component." + }, + { + "name": "AdvancedSelect", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive advanced select component.", + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"] + }, + { + "name": "Alert", + "category": "base", + "purpose": "Theme-aware, responsive alert component." + }, + { + "name": "AnnouncementBar", + "category": "blocks", + "purpose": "Accessible public announcement, emergency, maintenance, or status bar." + }, + { + "name": "AuthForm", + "category": "forms", + "purpose": "Reusable authentication form for sign-in, registration, recovery, reset, and MFA." + }, + { + "name": "AuthSplitLayout", + "category": "layout", + "purpose": "Responsive 50/50 authentication layout with content and form regions." + }, + { + "name": "Avatar", + "category": "base", + "purpose": "Theme-aware, responsive avatar component." + }, + { + "name": "AvatarGroup", + "category": "base", + "purpose": "Theme-aware, responsive avatar group component." + }, + { + "name": "BackToTop", + "category": "navigation", + "purpose": "Accessible scroll-to-top control with visibility threshold." + }, + { + "name": "Badge", + "category": "base", + "purpose": "Theme-aware, responsive badge component." + }, + { + "name": "Blockquote", + "category": "base", + "purpose": "Theme-aware, responsive blockquote component." + }, + { + "name": "Breadcrumb", + "category": "navigation", + "purpose": "Theme-aware, responsive breadcrumb component." + }, + { + "name": "Button", + "category": "base", + "purpose": "Theme-aware, responsive button component." + }, + { + "name": "ButtonGroup", + "category": "base", + "purpose": "Theme-aware, responsive button group component." + }, + { + "name": "Card", + "category": "base", + "purpose": "Theme-aware, responsive card component." + }, + { + "name": "Carousel", + "category": "base", + "purpose": "Theme-aware, responsive carousel component." + }, + { + "name": "Chart", + "category": "integrations", + "purpose": "Theme-aware, responsive chart component." + }, + { + "name": "ChatBubble", + "category": "base", + "purpose": "Theme-aware, responsive chat bubble component." + }, + { + "name": "Checkbox", + "category": "forms", + "purpose": "Theme-aware, responsive checkbox component." + }, + { + "name": "Clipboard", + "category": "integrations", + "purpose": "Theme-aware, responsive clipboard component." + }, + { + "name": "Collapse", + "category": "base", + "purpose": "Theme-aware, responsive collapse component." + }, + { + "name": "ColorPicker", + "category": "forms", + "purpose": "Theme-aware, responsive color picker component." + }, + { + "name": "Columns", + "category": "layout", + "purpose": "Theme-aware, responsive columns component." + }, + { + "name": "ComboBox", + "category": "advanced-forms", + "purpose": "Editable autocomplete combobox with local and remote suggestions.", + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"] + }, + { + "name": "Confetti", + "category": "integrations", + "purpose": "Theme-aware, responsive confetti component." + }, + { + "name": "Container", + "category": "layout", + "purpose": "Theme-aware, responsive container component." + }, + { + "name": "ContextMenu", + "category": "overlays", + "purpose": "Theme-aware, responsive context menu component." + }, + { + "name": "CopyMarkup", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive copy markup component." + }, + { + "name": "CTASection", + "category": "blocks", + "purpose": "Reusable closing call-to-action section with primary and secondary actions." + }, + { + "name": "CustomScrollbar", + "category": "layout", + "purpose": "Theme-aware, responsive custom scrollbar component." + }, + { + "name": "DataMap", + "category": "integrations", + "purpose": "Theme-aware, responsive data map component." + }, + { + "name": "DataTable", + "category": "integrations", + "purpose": "Theme-aware, responsive data table component." + }, + { + "name": "DatePicker", + "category": "base", + "purpose": "Theme-aware, responsive date picker component." + }, + { + "name": "DeviceFrame", + "category": "base", + "purpose": "Theme-aware, responsive device frame component." + }, + { + "name": "Divider", + "category": "layout", + "purpose": "Theme-aware, responsive divider component." + }, + { + "name": "DragAndDrop", + "category": "integrations", + "purpose": "Theme-aware, responsive drag and drop component." + }, + { + "name": "Drawer", + "category": "overlays", + "purpose": "Theme-aware, responsive drawer component." + }, + { + "name": "Dropdown", + "category": "overlays", + "purpose": "Theme-aware, responsive dropdown component." + }, + { + "name": "FeatureCard", + "category": "blocks", + "purpose": "Reusable linked feature or service card with icon, badge, description, and action." + }, + { + "name": "FeatureGrid", + "category": "layout", + "purpose": "Responsive equal-height grid for feature and service cards." + }, + { + "name": "FeatureIconCard", + "category": "blocks", + "purpose": "Feature card with a prominent themed icon treatment." + }, + { + "name": "FileInput", + "category": "forms", + "purpose": "Theme-aware, responsive file input component." + }, + { + "name": "FileUpload", + "category": "integrations", + "purpose": "Theme-aware, responsive file upload component." + }, + { + "name": "FileUploadProgress", + "category": "base", + "purpose": "Theme-aware, responsive file upload progress component." + }, + { + "name": "Footer", + "category": "navigation", + "purpose": "Responsive application footer with structured links and pre/post content slots." + }, + { + "name": "Grid", + "category": "layout", + "purpose": "Theme-aware, responsive grid component." + }, + { + "name": "Hero", + "category": "blocks", + "purpose": "Reusable public-page hero with actions, trust items, badges, and visual slots." + }, + { + "name": "HeroActions", + "category": "base", + "purpose": "Responsive action group for hero and call-to-action sections." + }, + { + "name": "Image", + "category": "layout", + "purpose": "Theme-aware, responsive image component." + }, + { + "name": "Input", + "category": "forms", + "purpose": "Theme-aware, responsive input component." + }, + { + "name": "InputGroup", + "category": "forms", + "purpose": "Theme-aware, responsive input group component." + }, + { + "name": "InputNumber", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive input number component." + }, + { + "name": "Kbd", + "category": "layout", + "purpose": "Theme-aware, responsive kbd component." + }, + { + "name": "LayoutSplitter", + "category": "layout", + "purpose": "Theme-aware, responsive layout splitter component." + }, + { + "name": "LegendIndicator", + "category": "base", + "purpose": "Theme-aware, responsive legend indicator component." + }, + { + "name": "Link", + "category": "layout", + "purpose": "Theme-aware, responsive link component." + }, + { + "name": "List", + "category": "base", + "purpose": "Theme-aware, responsive list component." + }, + { + "name": "ListGroup", + "category": "base", + "purpose": "Theme-aware, responsive list group component." + }, + { + "name": "Map", + "category": "integrations", + "purpose": "Theme-aware, responsive map component." + }, + { + "name": "MarketingSectionHeader", + "category": "blocks", + "purpose": "Marketing section heading with an optional linked action." + }, + { + "name": "Marquee", + "category": "base", + "purpose": "Theme-aware, responsive marquee component." + }, + { + "name": "MegaMenu", + "category": "navigation", + "purpose": "Theme-aware, responsive mega menu component." + }, + { + "name": "MetricCard", + "category": "blocks", + "purpose": "Single statistic or operational metric with icon, trend, and optional action." + }, + { + "name": "MetricGrid", + "category": "layout", + "purpose": "Responsive collection of metric cards." + }, + { + "name": "Modal", + "category": "overlays", + "purpose": "Theme-aware, responsive modal component." + }, + { + "name": "Nav", + "category": "navigation", + "purpose": "Theme-aware, responsive nav component." + }, + { + "name": "Navbar", + "category": "navigation", + "purpose": "Theme-aware, responsive navbar component." + }, + { + "name": "PageHeader", + "category": "blocks", + "purpose": "Public and application page header with breadcrumbs, metadata, and actions." + }, + { + "name": "Pagination", + "category": "navigation", + "purpose": "Theme-aware, responsive pagination component." + }, + { + "name": "PinInput", + "category": "advanced-forms", + "purpose": "Secure multi-cell PIN and verification-code input with regex and paste support.", + "events": ["input", "change", "complete", "paste", "clear", "error"] + }, + { + "name": "Popover", + "category": "overlays", + "purpose": "Theme-aware, responsive popover component." + }, + { + "name": "PortalDashboard", + "category": "blocks", + "purpose": "Responsive portal dashboard with metrics, actions, tasks, and updates." + }, + { + "name": "PreferenceSwitcher", + "category": "navigation", + "purpose": "Accessible theme, accent color, and language preference controls." + }, + { + "name": "Progress", + "category": "base", + "purpose": "Theme-aware, responsive progress component." + }, + { + "name": "PublicPageShell", + "category": "layout", + "purpose": "Consistent structural wrapper for public-facing pages." + }, + { + "name": "Radio", + "category": "forms", + "purpose": "Theme-aware, responsive radio component." + }, + { + "name": "RangeSlider", + "category": "forms", + "purpose": "Theme-aware, responsive range slider component." + }, + { + "name": "Rating", + "category": "base", + "purpose": "Theme-aware, responsive rating component." + }, + { + "name": "Scrollspy", + "category": "navigation", + "purpose": "Theme-aware, responsive scrollspy component." + }, + { + "name": "SearchBox", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive search box component." + }, + { + "name": "Section", + "category": "layout", + "purpose": "Theme-aware page section with consistent spacing, width, background, and border controls." + }, + { + "name": "SectionHeader", + "category": "layout", + "purpose": "Reusable accessible section heading with eyebrow, title, description, icon, and actions." + }, + { + "name": "Select", + "category": "forms", + "purpose": "Theme-aware, responsive select component." + }, + { + "name": "Sidebar", + "category": "navigation", + "purpose": "Theme-aware, responsive sidebar component." + }, + { + "name": "Skeleton", + "category": "base", + "purpose": "Theme-aware, responsive skeleton component." + }, + { + "name": "Spinner", + "category": "base", + "purpose": "Theme-aware, responsive spinner component." + }, + { + "name": "SplitHero", + "category": "blocks", + "purpose": "Two-column hero with configurable content and visual placement." + }, + { + "name": "StatsBar", + "category": "blocks", + "purpose": "Compact responsive statistics strip." + }, + { + "name": "Stepper", + "category": "navigation", + "purpose": "Theme-aware, responsive stepper component." + }, + { + "name": "StrongPassword", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive strong password component." + }, + { + "name": "StyledIcon", + "category": "base", + "purpose": "Theme-aware, responsive styled icon component." + }, + { + "name": "Switch", + "category": "forms", + "purpose": "Theme-aware, responsive switch component." + }, + { + "name": "Table", + "category": "tables", + "purpose": "Theme-aware, responsive table component." + }, + { + "name": "Tabs", + "category": "navigation", + "purpose": "Theme-aware, responsive tabs component." + }, + { + "name": "Textarea", + "category": "forms", + "purpose": "Theme-aware, responsive textarea component." + }, + { + "name": "TextLink", + "category": "layout", + "purpose": "Styled inline action link with icons, arrows, external state, and disabled handling." + }, + { + "name": "Timeline", + "category": "base", + "purpose": "Theme-aware, responsive timeline component." + }, + { + "name": "TimePicker", + "category": "forms", + "purpose": "Theme-aware, responsive time picker component." + }, + { + "name": "Toast", + "category": "base", + "purpose": "Theme-aware, responsive toast component." + }, + { + "name": "ToastNotifications", + "category": "integrations", + "purpose": "Theme-aware, responsive toast notifications component." + }, + { + "name": "ToggleCount", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive toggle count component." + }, + { + "name": "TogglePassword", + "category": "advanced-forms", + "purpose": "Accessible password field with optional show and hide controls.", + "events": ["input", "change", "toggle"] + }, + { + "name": "Tooltip", + "category": "overlays", + "purpose": "Theme-aware, responsive tooltip component." + }, + { + "name": "TreeView", + "category": "base", + "purpose": "Theme-aware, responsive tree view component." + }, + { + "name": "Typography", + "category": "layout", + "purpose": "Theme-aware, responsive typography component." + }, + { + "name": "WysiwygEditor", + "category": "integrations", + "purpose": "Theme-aware, responsive wysiwyg editor component." + } + ] +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/component-reference.json b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/component-reference.json new file mode 100644 index 00000000..8a319957 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/component-reference.json @@ -0,0 +1,9773 @@ +{ + "generatedFrom": "packages/ui/components/*.wrn", + "count": 108, + "components": [ + { + "name": "Accordion", + "mount": "Accordion", + "category": "base", + "purpose": "Theme-aware, responsive accordion component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"accordion\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "defaultOpen", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "alwaysOpen", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "indicator", + "type": "string", + "required": false, + "default": "\"plus\"" + }, + { + "name": "indicatorPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "showIndicator", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "bordered", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "separated", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "flush", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "contentItalic", + "type": "boolean", + "required": false, + "default": "false" + } + ], + "slots": [], + "events": ["change", "open", "close"], + "source": "components/Accordion.wrn" + }, + { + "name": "AdvancedDatePicker", + "mount": "AdvancedDatePicker", + "category": "integrations", + "purpose": "Theme-aware, responsive advanced date picker component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Advanced Date Picker\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change", "open", "close", "clear"], + "source": "components/AdvancedDatePicker.wrn" + }, + { + "name": "AdvancedRangeSlider", + "mount": "AdvancedRangeSlider", + "category": "integrations", + "purpose": "Theme-aware, responsive advanced range slider component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Advanced Range Slider\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change", "start", "end"], + "source": "components/AdvancedRangeSlider.wrn" + }, + { + "name": "AdvancedSelect", + "mount": "AdvancedSelect", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive advanced select component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Advanced Select\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "values", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "groups", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Select an option\"" + }, + { + "name": "placeholderIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "searchPlaceholder", + "type": "string", + "required": false, + "default": "\"Search options…\"" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "searchable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "defaultOpen", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "clearable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "allowEmpty", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "tags", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "loading", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "loadingLabel", + "type": "string", + "required": false, + "default": "\"Loading options…\"" + }, + { + "name": "emptyLabel", + "type": "string", + "required": false, + "default": "\"No options found\"" + }, + { + "name": "selectedOptionsLabel", + "type": "string", + "required": false, + "default": "\"Selected options\"" + }, + { + "name": "clearLabel", + "type": "string", + "required": false, + "default": "\"Clear selection\"" + }, + { + "name": "createLabel", + "type": "string", + "required": false, + "default": "\"Create\"" + }, + { + "name": "loadMoreLabel", + "type": "string", + "required": false, + "default": "\"Load more\"" + }, + { + "name": "searchMode", + "type": "string", + "required": false, + "default": "\"contains\"" + }, + { + "name": "searchFields", + "type": "string", + "required": false, + "default": "\"label,description\"" + }, + { + "name": "minSearchLength", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "searchResultLimit", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "maxSelections", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "showCounter", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "counterTemplate", + "type": "string", + "required": false, + "default": "\"{selected} selected\"" + }, + { + "name": "optionTemplate", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "selectedTemplate", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "closeOnSelect", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "scrollToSelected", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fixed", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "remote", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "remoteUrl", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "remoteQueryParam", + "type": "string", + "required": false, + "default": "\"q\"" + }, + { + "name": "remoteDebounce", + "type": "number", + "required": false, + "default": "250" + }, + { + "name": "remoteAutoLoad", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "infinite", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "hasMore", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "page", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"], + "source": "components/AdvancedSelect.wrn" + }, + { + "name": "Alert", + "mount": "Alert", + "category": "base", + "purpose": "Theme-aware, responsive alert component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"info\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"soft\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "radius", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "shadow", + "type": "string", + "required": false, + "default": "\"sm\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Alert\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "actions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "showIcon", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "dismissible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dismissLabel", + "type": "string", + "required": false, + "default": "\"Dismiss alert\"" + }, + { + "name": "role", + "type": "string", + "required": false, + "default": "\"alert\"" + }, + { + "name": "live", + "type": "string", + "required": false, + "default": "\"polite\"" + }, + { + "name": "linkLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "linkHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "false" + } + ], + "slots": [], + "events": ["dismiss", "action"], + "source": "components/alert.wrn" + }, + { + "name": "AnnouncementBar", + "mount": "AnnouncementBar", + "category": "blocks", + "purpose": "Accessible public announcement, emergency, maintenance, or status bar.", + "props": [ + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badgeIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "message", + "type": "string", + "required": false, + "default": "\"Announcement\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--megaphone]\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "dismissible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dismissLabel", + "type": "string", + "required": false, + "default": "\"Dismiss announcement\"" + }, + { + "name": "sticky", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"soft\"" + }, + { + "name": "role", + "type": "string", + "required": false, + "default": "\"status\"" + }, + { + "name": "live", + "type": "string", + "required": false, + "default": "\"polite\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/AnnouncementBar.wrn" + }, + { + "name": "AuthForm", + "mount": "AuthForm", + "category": "forms", + "purpose": "Reusable authentication form for sign-in, registration, recovery, reset, and MFA.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "mode", + "type": "string", + "required": false, + "default": "\"sign-in\"" + }, + { + "name": "action", + "type": "string", + "required": false, + "default": "\"/api/auth/login\"" + }, + { + "name": "method", + "type": "string", + "required": false, + "default": "\"post\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Sign in\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "returnTo", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "schema", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "showRemember", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showName", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "submitLabel", + "type": "string", + "required": false, + "default": "\"Continue\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["submit", "change", "input", "focus", "blur"], + "source": "components/AuthForm.wrn" + }, + { + "name": "AuthSplitLayout", + "mount": "AuthSplitLayout", + "category": "layout", + "purpose": "Responsive 50/50 authentication layout with content and form regions.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"Secure identity\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Welcome back\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "brand", + "type": "string", + "required": false, + "default": "\"Police Management System\"" + }, + { + "name": "features", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["aside-extra", "form"], + "events": [], + "source": "components/AuthSplitLayout.wrn" + }, + { + "name": "Avatar", + "mount": "Avatar", + "category": "base", + "purpose": "Theme-aware, responsive avatar component.", + "props": [ + { + "name": "src", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "alt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "initials", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "shape", + "type": "string", + "required": false, + "default": "\"circle\"" + }, + { + "name": "status", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "statusLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "statusPosition", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badgeIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badgeLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "tooltip", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "loading", + "type": "string", + "required": false, + "default": "\"lazy\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["load", "error", "click"], + "source": "components/avatar.wrn" + }, + { + "name": "AvatarGroup", + "mount": "AvatarGroup", + "category": "base", + "purpose": "Theme-aware, responsive avatar group component.", + "props": [ + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "shape", + "type": "string", + "required": false, + "default": "\"circle\"" + }, + { + "name": "layout", + "type": "string", + "required": false, + "default": "\"stack\"" + }, + { + "name": "maxVisible", + "type": "number", + "required": false, + "default": "4" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "borderColor", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "showTooltips", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "overflowLabel", + "type": "string", + "required": false, + "default": "\"Show remaining members\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["overflow"], + "source": "components/AvatarGroup.wrn" + }, + { + "name": "BackToTop", + "mount": "BackToTop", + "category": "navigation", + "purpose": "Accessible scroll-to-top control with visibility threshold.", + "props": [ + { + "name": "threshold", + "type": "number", + "required": false, + "default": "500" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Back to top\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Scroll back to top\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--arrow-up]\"" + }, + { + "name": "position", + "type": "string", + "required": false, + "default": "\"right\"" + }, + { + "name": "offset", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "behavior", + "type": "string", + "required": false, + "default": "\"smooth\"" + }, + { + "name": "showProgress", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/BackToTop.wrn" + }, + { + "name": "Badge", + "mount": "Badge", + "category": "base", + "purpose": "Theme-aware, responsive badge component.", + "props": [ + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Badge\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "shape", + "type": "string", + "required": false, + "default": "\"pill\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "dot", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dotOnly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dotLabel", + "type": "string", + "required": false, + "default": "\"Status\"" + }, + { + "name": "animated", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "avatarSrc", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "avatarAlt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "dismissible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dismissLabel", + "type": "string", + "required": false, + "default": "\"Remove badge\"" + }, + { + "name": "truncate", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"12rem\"" + }, + { + "name": "anchorLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "anchorIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"inline\"" + }, + { + "name": "anchorLabelText", + "type": "string", + "required": false, + "default": "\"Badge anchor\"" + } + ], + "slots": [], + "events": ["dismiss"], + "source": "components/Badge.wrn" + }, + { + "name": "Blockquote", + "mount": "Blockquote", + "category": "base", + "purpose": "Theme-aware, responsive blockquote component.", + "props": [ + { + "name": "quote", + "type": "string", + "required": false, + "default": "\"I just wanted to say that I'm very happy with my purchase so far. The documentation is outstanding - clear and detailed.\"" + }, + { + "name": "citation", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "citationTitle", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "citationUrl", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "avatarSrc", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "avatarAlt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "quoteMark", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "italic", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Blockquote.wrn" + }, + { + "name": "Breadcrumb", + "mount": "Breadcrumb", + "category": "navigation", + "purpose": "Theme-aware, responsive breadcrumb component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Breadcrumb\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["navigate", "click"], + "source": "components/Breadcrumb.wrn" + }, + { + "name": "Button", + "mount": "Button", + "category": "base", + "purpose": "Theme-aware, responsive button component.", + "props": [ + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Button\"" + }, + { + "name": "loadingLabel", + "type": "string", + "required": false, + "default": "\"Loading…\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "as", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "target", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "rel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"button\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "loading", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "pill", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "ariaPressed", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "ariaExpanded", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "ariaControls", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "autofocus", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "controlClass", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["click", "focus", "blur"], + "source": "components/button.wrn" + }, + { + "name": "ButtonGroup", + "mount": "ButtonGroup", + "category": "base", + "purpose": "Theme-aware, responsive button group component.", + "props": [ + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "responsive", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "attached", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "selectable", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "toolbar", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Button group\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["click", "select", "change"], + "source": "components/ButtonGroup.wrn" + }, + { + "name": "Card", + "mount": "Card", + "category": "base", + "purpose": "Theme-aware, responsive card component.", + "props": [ + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Card title\"" + }, + { + "name": "subtitle", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "header", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "footer", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "imageSrc", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "imageAlt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "imagePosition", + "type": "string", + "required": false, + "default": "\"top\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "headerActions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "navigation", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "activeNav", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "mobileNavigation", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "alertTitle", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "alertDescription", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "empty", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "emptyTitle", + "type": "string", + "required": false, + "default": "\"No data to show\"" + }, + { + "name": "emptyIcon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--inbox]\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "layout", + "type": "string", + "required": false, + "default": "\"vertical\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "hover", + "type": "string", + "required": false, + "default": "\"none\"" + }, + { + "name": "scrollable", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "maxHeight", + "type": "string", + "required": false, + "default": "\"18rem\"" + }, + { + "name": "dismissible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["click", "action", "navigate", "dismiss", "load", "error"], + "source": "components/Card.wrn" + }, + { + "name": "Carousel", + "mount": "Carousel", + "category": "base", + "purpose": "Theme-aware, responsive carousel component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "activeIndex", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "slidesPerView", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"0.75rem\"" + }, + { + "name": "showPagination", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isAutoPlay", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "autoplayInterval", + "type": "number", + "required": false, + "default": "4000" + }, + { + "name": "isInfiniteLoop", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isRTL", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isCentered", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isDraggable", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isAutoHeight", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isSnap", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showCounter", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "thumbnails", + "type": "string", + "required": false, + "default": "\"none\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Content carousel\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [ + "initialize", + "change", + "previous", + "next", + "play", + "pause", + "reachStart", + "reachEnd", + "dragStart", + "dragEnd" + ], + "source": "components/carousel.wrn" + }, + { + "name": "Chart", + "mount": "Chart", + "category": "integrations", + "purpose": "Theme-aware, responsive chart component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Chart\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "dataPointClick", "legendToggle"], + "source": "components/Chart.wrn" + }, + { + "name": "ChatBubble", + "mount": "ChatBubble", + "category": "base", + "purpose": "Theme-aware, responsive chat bubble component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "oneSided", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showAvatars", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showMetadata", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Conversation\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["action", "messageClick", "avatarClick", "linkClick"], + "source": "components/ChatBubble.wrn" + }, + { + "name": "Checkbox", + "mount": "Checkbox", + "category": "forms", + "purpose": "Theme-aware, responsive checkbox component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Checkbox\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"on\"" + }, + { + "name": "values", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "checked", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "indeterminate", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"vertical\"" + }, + { + "name": "card", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "rightAligned", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "list", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change", "focus", "blur", "invalid"], + "source": "components/Checkbox.wrn" + }, + { + "name": "Clipboard", + "mount": "Clipboard", + "category": "integrations", + "purpose": "Theme-aware, responsive clipboard component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Clipboard\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["copy", "success", "error"], + "source": "components/Clipboard.wrn" + }, + { + "name": "Collapse", + "mount": "Collapse", + "category": "base", + "purpose": "Theme-aware, responsive collapse component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "mode", + "type": "string", + "required": false, + "default": "\"panel\"" + }, + { + "name": "initialOpenIndexes", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Collapsible content\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["toggle", "open", "close"], + "source": "components/Collapse.wrn" + }, + { + "name": "ColorPicker", + "mount": "ColorPicker", + "category": "forms", + "purpose": "Theme-aware, responsive color picker component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Color\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"#2563eb\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur"], + "source": "components/ColorPicker.wrn" + }, + { + "name": "Columns", + "mount": "Columns", + "category": "layout", + "purpose": "Theme-aware, responsive columns component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Columns.wrn" + }, + { + "name": "ComboBox", + "mount": "ComboBox", + "category": "advanced-forms", + "purpose": "Editable autocomplete combobox with local and remote suggestions.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"ComboBox\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "groups", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Search or select an option\"" + }, + { + "name": "searchPlaceholder", + "type": "string", + "required": false, + "default": "\"Start typing…\"" + }, + { + "name": "clearable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "allowCustomValue", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "loading", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "loadingLabel", + "type": "string", + "required": false, + "default": "\"Loading suggestions…\"" + }, + { + "name": "emptyLabel", + "type": "string", + "required": false, + "default": "\"No matching options\"" + }, + { + "name": "clearLabel", + "type": "string", + "required": false, + "default": "\"Clear value\"" + }, + { + "name": "toggleLabel", + "type": "string", + "required": false, + "default": "\"Toggle suggestions\"" + }, + { + "name": "searchMode", + "type": "string", + "required": false, + "default": "\"contains\"" + }, + { + "name": "searchFields", + "type": "string", + "required": false, + "default": "\"label,description\"" + }, + { + "name": "minSearchLength", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "searchResultLimit", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "optionTemplate", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "defaultOpen", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "closeOnSelect", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fixed", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"off\"" + }, + { + "name": "remote", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "remoteUrl", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "remoteQueryParam", + "type": "string", + "required": false, + "default": "\"q\"" + }, + { + "name": "remoteDebounce", + "type": "number", + "required": false, + "default": "250" + }, + { + "name": "remoteAutoLoad", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "infinite", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "hasMore", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "page", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "loadMoreLabel", + "type": "string", + "required": false, + "default": "\"Load more\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"], + "source": "components/Combobox.wrn" + }, + { + "name": "Confetti", + "mount": "Confetti", + "category": "integrations", + "purpose": "Theme-aware, responsive confetti component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Confetti\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["start", "complete"], + "source": "components/Confetti.wrn" + }, + { + "name": "Container", + "mount": "Container", + "category": "layout", + "purpose": "Theme-aware, responsive container component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Container.wrn" + }, + { + "name": "ContextMenu", + "mount": "ContextMenu", + "category": "overlays", + "purpose": "Theme-aware, responsive context menu component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Context Menu\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close", "select"], + "source": "components/ContextMenu.wrn" + }, + { + "name": "CopyMarkup", + "mount": "CopyMarkup", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive copy markup component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Copy Markup\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"text\"" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["copy", "success", "error"], + "source": "components/CopyMarkup.wrn" + }, + { + "name": "CTASection", + "mount": "CTASection", + "category": "blocks", + "purpose": "Reusable closing call-to-action section with primary and secondary actions.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Ready to get started?\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"center\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"Get started\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"#\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "backgroundImage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default", "actions", "visual", "footer"], + "events": [], + "source": "components/CTASection.wrn" + }, + { + "name": "CustomScrollbar", + "mount": "CustomScrollbar", + "category": "layout", + "purpose": "Theme-aware, responsive custom scrollbar component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["scroll"], + "source": "components/CustomScrollbar.wrn" + }, + { + "name": "DataMap", + "mount": "DataMap", + "category": "integrations", + "purpose": "Theme-aware, responsive data map component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Data Map\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "change"], + "source": "components/DataMap.wrn" + }, + { + "name": "DataTable", + "mount": "DataTable", + "category": "integrations", + "purpose": "Theme-aware, responsive data table component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "caption", + "type": "string", + "required": false, + "default": "\"Data Table\"" + }, + { + "name": "columns", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "rows", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "striped", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["sort", "select", "change", "rowClick", "pageChange"], + "source": "components/DataTable.wrn" + }, + { + "name": "DatePicker", + "mount": "DatePicker", + "category": "base", + "purpose": "Theme-aware, responsive date picker component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Date Picker\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"date\"" + }, + { + "name": "locale", + "type": "string", + "required": false, + "default": "\"en-US\"" + }, + { + "name": "firstDayOfWeek", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "months", + "type": "string", + "required": false, + "default": "[{ label: \"Jan\", value: \"01\" }, { label: \"Feb\", value: \"02\" }, { label: \"Mar\", value: \"03\" }, { label: \"Apr\", value: \"04\" }, { label: \"May\", value: \"05\" }, { label: \"Jun\", value: \"06\" }, { label: \"Jul\", value: \"07\" }, { label: \"Aug\", value: \"08\" }, { label: \"Sep\", value: \"09\" }, { label: \"Oct\", value: \"10\" }, { label: \"Nov\", value: \"11\" }, { label: \"Dec\", value: \"12\" }]" + }, + { + "name": "days", + "type": "string", + "required": false, + "default": "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]" + }, + { + "name": "years", + "type": "string", + "required": false, + "default": "[2024, 2025, 2026, 2027, 2028, 2029, 2030]" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "open", "close", "focus", "blur", "invalid"], + "source": "components/DatePicker.wrn" + }, + { + "name": "DeviceFrame", + "mount": "DeviceFrame", + "category": "base", + "purpose": "Theme-aware, responsive device frame component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Device Frame\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "device", + "type": "string", + "required": false, + "default": "\"phone\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"portrait\"" + }, + { + "name": "src", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "srcdoc", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "frameTitle", + "type": "string", + "required": false, + "default": "\"Device preview\"" + }, + { + "name": "showToolbar", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "allow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["change", "rotate"], + "source": "components/DeviceFrame.wrn" + }, + { + "name": "Divider", + "mount": "Divider", + "category": "layout", + "purpose": "Theme-aware, responsive divider component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/Divider.wrn" + }, + { + "name": "DragAndDrop", + "mount": "DragAndDrop", + "category": "integrations", + "purpose": "Theme-aware, responsive drag and drop component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Drag And Drop\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["dragStart", "dragEnd", "dragEnter", "dragLeave", "drop", "change"], + "source": "components/DragAndDrop.wrn" + }, + { + "name": "Drawer", + "mount": "Drawer", + "category": "overlays", + "purpose": "Theme-aware, responsive drawer component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Drawer\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close"], + "source": "components/Drawer.wrn" + }, + { + "name": "Dropdown", + "mount": "Dropdown", + "category": "overlays", + "purpose": "Theme-aware, responsive dropdown component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Open menu\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"end\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["trigger", "header", "footer"], + "events": ["toggle", "open", "close", "select"], + "source": "components/Dropdown.wrn" + }, + { + "name": "FeatureCard", + "mount": "FeatureCard", + "category": "blocks", + "purpose": "Reusable linked feature or service card with icon, badge, description, and action.", + "props": [ + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Feature\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"Learn more\"" + }, + { + "name": "actionIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badgeColor", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "hover", + "type": "string", + "required": false, + "default": "\"lift\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["icon", "default", "footer"], + "events": [], + "source": "components/FeatureCard.wrn" + }, + { + "name": "FeatureGrid", + "mount": "FeatureGrid", + "category": "layout", + "purpose": "Responsive equal-height grid for feature and service cards.", + "props": [ + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "tabletColumns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "mobileColumns", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "minItemWidth", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "equalHeight", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"stretch\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"full\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/FeatureGrid.wrn" + }, + { + "name": "FeatureIconCard", + "mount": "FeatureIconCard", + "category": "blocks", + "purpose": "Feature card with a prominent themed icon treatment.", + "props": [ + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--sparkles]\"" + }, + { + "name": "iconSize", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "iconVariant", + "type": "string", + "required": false, + "default": "\"soft\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Feature\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"Explore\"" + }, + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "hover", + "type": "string", + "required": false, + "default": "\"lift\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default", "footer"], + "events": [], + "source": "components/FeatureIconCard.wrn" + }, + { + "name": "FileInput", + "mount": "FileInput", + "category": "forms", + "purpose": "Theme-aware, responsive file input component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"File\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Choose a file\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--upload]\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "accept", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "select", "clear", "invalid"], + "source": "components/FileInput.wrn" + }, + { + "name": "FileUpload", + "mount": "FileUpload", + "category": "integrations", + "purpose": "Theme-aware, responsive file upload component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"File Upload\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "upload", "progress", "success", "error", "cancel", "remove"], + "source": "components/FileUpload.wrn" + }, + { + "name": "FileUploadProgress", + "mount": "FileUploadProgress", + "category": "base", + "purpose": "Theme-aware, responsive file upload progress component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Progress\"" + }, + { + "name": "value", + "type": "number", + "required": false, + "default": "50" + }, + { + "name": "max", + "type": "number", + "required": false, + "default": "100" + }, + { + "name": "showValue", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fileName", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "fileSize", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "uploadedSize", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "status", + "type": "string", + "required": false, + "default": "\"uploading\"" + }, + { + "name": "cancelLabel", + "type": "string", + "required": false, + "default": "\"Cancel upload\"" + }, + { + "name": "retryLabel", + "type": "string", + "required": false, + "default": "\"Retry upload\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["cancel", "retry", "complete"], + "source": "components/FileUploadProgress.wrn" + }, + { + "name": "Footer", + "mount": "Footer", + "category": "navigation", + "purpose": "Responsive application footer with structured links and pre/post content slots.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Footer navigation\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"compact\"" + }, + { + "name": "copyright", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["pre-footer", "copyright-left", "copyright-right", "post-footer"], + "events": ["select", "action"], + "source": "components/Footer.wrn" + }, + { + "name": "Grid", + "mount": "Grid", + "category": "layout", + "purpose": "Theme-aware, responsive grid component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Grid.wrn" + }, + { + "name": "Hero", + "mount": "Hero", + "category": "blocks", + "purpose": "Reusable public-page hero with actions, trust items, badges, and visual slots.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Build something remarkable\"" + }, + { + "name": "highlight", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "tertiaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "tertiaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badges", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "trustItems", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["eyebrow", "actions", "trust", "default", "visual", "footer"], + "events": [], + "source": "components/Hero.wrn" + }, + { + "name": "HeroActions", + "mount": "HeroActions", + "category": "base", + "purpose": "Responsive action group for hero and call-to-action sections.", + "props": [ + { + "name": "actions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "stackOnMobile", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fullWidthMobile", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/HeroActions.wrn" + }, + { + "name": "Image", + "mount": "Image", + "category": "layout", + "purpose": "Theme-aware, responsive image component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "src", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "alt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "width", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "height", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "loading", + "type": "string", + "required": false, + "default": "\"lazy\"" + }, + { + "name": "rounded", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Image.wrn" + }, + { + "name": "Input", + "mount": "Input", + "category": "forms", + "purpose": "Theme-aware, responsive input component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Input\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"text\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inputmode", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "minlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "maxlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "pattern", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "invalid", "keydown", "keyup"], + "source": "components/Input.wrn" + }, + { + "name": "InputGroup", + "mount": "InputGroup", + "category": "forms", + "purpose": "Theme-aware, responsive input group component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Input group\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"text\"" + }, + { + "name": "startText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "endText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "submit", "action"], + "source": "components/InputGroup.wrn" + }, + { + "name": "InputNumber", + "mount": "InputNumber", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive input number component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"quantity\"" + }, + { + "name": "value", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "precision", + "type": "string", + "required": false, + "default": "\"auto\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "prefix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "suffix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"off\"" + }, + { + "name": "inputMode", + "type": "string", + "required": false, + "default": "\"decimal\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "inputDisabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "buttonsDisabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "allowInput", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "keyboard", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "wheel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "clamp", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showButtons", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showValidationMessage", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "decrementLabel", + "type": "string", + "required": false, + "default": "\"Decrease value\"" + }, + { + "name": "incrementLabel", + "type": "string", + "required": false, + "default": "\"Increase value\"" + }, + { + "name": "controlsLabel", + "type": "string", + "required": false, + "default": "\"Quantity controls\"" + }, + { + "name": "requiredMessage", + "type": "string", + "required": false, + "default": "\"A value is required.\"" + }, + { + "name": "minMessage", + "type": "string", + "required": false, + "default": "\"Value is below the minimum.\"" + }, + { + "name": "maxMessage", + "type": "string", + "required": false, + "default": "\"Value is above the maximum.\"" + } + ], + "slots": [], + "events": ["input", "change", "increment", "decrement"], + "source": "components/InputNumber.wrn" + }, + { + "name": "Kbd", + "mount": "Kbd", + "category": "layout", + "purpose": "Theme-aware, responsive kbd component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"⌘ K\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Kbd.wrn" + }, + { + "name": "LayoutSplitter", + "mount": "LayoutSplitter", + "category": "layout", + "purpose": "Theme-aware, responsive layout splitter component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["resizeStart", "resize", "resizeEnd"], + "source": "components/LayoutSplitter.wrn" + }, + { + "name": "LegendIndicator", + "mount": "LegendIndicator", + "category": "base", + "purpose": "Theme-aware, responsive legend indicator component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Legend Indicator\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["toggle", "select"], + "source": "components/LegendIndicator.wrn" + }, + { + "name": "Link", + "mount": "Link", + "category": "layout", + "purpose": "Theme-aware, responsive link component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Link\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"#\"" + }, + { + "name": "target", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "rel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "external", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Link.wrn" + }, + { + "name": "List", + "mount": "List", + "category": "base", + "purpose": "Theme-aware, responsive list component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"List\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/List.wrn" + }, + { + "name": "ListGroup", + "mount": "ListGroup", + "category": "base", + "purpose": "Theme-aware, responsive list group component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"List Group\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "change"], + "source": "components/ListGroup.wrn" + }, + { + "name": "Map", + "mount": "Map", + "category": "integrations", + "purpose": "Theme-aware, responsive map component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Map\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Map.wrn" + }, + { + "name": "MarketingSectionHeader", + "mount": "MarketingSectionHeader", + "category": "blocks", + "purpose": "Marketing section heading with an optional linked action.", + "props": [ + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"split\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionExternal", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["icon", "actions", "default"], + "events": [], + "source": "components/MarketingSectionHeader.wrn" + }, + { + "name": "Marquee", + "mount": "Marquee", + "category": "base", + "purpose": "Theme-aware, responsive marquee component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Marquee\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Marquee.wrn" + }, + { + "name": "MegaMenu", + "mount": "MegaMenu", + "category": "navigation", + "purpose": "Theme-aware, responsive mega menu component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Mega Menu\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close", "select"], + "source": "components/MegaMenu.wrn" + }, + { + "name": "MetricCard", + "mount": "MetricCard", + "category": "blocks", + "purpose": "Single statistic or operational metric with icon, trend, and optional action.", + "props": [ + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Metric\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"0\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "prefix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "suffix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "trend", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "trendLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "trendDirection", + "type": "string", + "required": false, + "default": "\"neutral\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/MetricCard.wrn" + }, + { + "name": "MetricGrid", + "mount": "MetricGrid", + "category": "layout", + "purpose": "Responsive collection of metric cards.", + "props": [ + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "4" + }, + { + "name": "tabletColumns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "mobileColumns", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "equalHeight", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "dividers", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/MetricGrid.wrn" + }, + { + "name": "Modal", + "mount": "Modal", + "category": "overlays", + "purpose": "Theme-aware, responsive modal component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Modal\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close", "cancel", "confirm"], + "source": "components/Modal.wrn" + }, + { + "name": "Nav", + "mount": "Nav", + "category": "navigation", + "purpose": "Theme-aware, responsive nav component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Nav\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "change"], + "source": "components/Nav.wrn" + }, + { + "name": "Navbar", + "mount": "Navbar", + "category": "navigation", + "purpose": "Theme-aware, responsive navbar component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Primary navigation\"" + }, + { + "name": "topbarLabel", + "type": "string", + "required": false, + "default": "\"Utility navigation\"" + }, + { + "name": "brand", + "type": "string", + "required": false, + "default": "{}" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "actions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "sticky", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "openOnHover", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"full\"" + }, + { + "name": "mobileLabel", + "type": "string", + "required": false, + "default": "\"Toggle navigation\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["topbar", "actions"], + "events": ["toggle", "open", "close", "select", "action"], + "source": "components/Navbar.wrn" + }, + { + "name": "PageHeader", + "mount": "PageHeader", + "category": "blocks", + "purpose": "Public and application page header with breadcrumbs, metadata, and actions.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showBreadcrumbs", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "breadcrumbs", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["meta", "actions", "default"], + "events": [], + "source": "components/PageHeader.wrn" + }, + { + "name": "Pagination", + "mount": "Pagination", + "category": "navigation", + "purpose": "Theme-aware, responsive pagination component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Pagination\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["change", "previous", "next"], + "source": "components/Pagination.wrn" + }, + { + "name": "PinInput", + "mount": "PinInput", + "category": "advanced-forms", + "purpose": "Secure multi-cell PIN and verification-code input with regex and paste support.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Verification code\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"pin\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "length", + "type": "number", + "required": false, + "default": "4" + }, + { + "name": "pattern", + "type": "string", + "required": false, + "default": "\"[0-9]\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"text\"" + }, + { + "name": "inputMode", + "type": "string", + "required": false, + "default": "\"numeric\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"○\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"one-time-code\"" + }, + { + "name": "masked", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "autoFocus", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "autoSubmit", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "allowPaste", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "clearable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "clearLabel", + "type": "string", + "required": false, + "default": "\"Clear code\"" + }, + { + "name": "separator", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "groupSize", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "complete", "paste", "clear", "error"], + "source": "components/PinInput.wrn" + }, + { + "name": "Popover", + "mount": "Popover", + "category": "overlays", + "purpose": "Theme-aware, responsive popover component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Popover\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close"], + "source": "components/Popover.wrn" + }, + { + "name": "PortalDashboard", + "mount": "PortalDashboard", + "category": "blocks", + "purpose": "Responsive portal dashboard with metrics, actions, tasks, and updates.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"Overview\"" + }, + { + "name": "eyebrowKey", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Dashboard\"" + }, + { + "name": "titleKey", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "descriptionKey", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "userName", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "metrics", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "actions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "updates", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "tasks", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["hero-action"], + "events": ["action", "navigate"], + "source": "components/PortalDashboard.wrn" + }, + { + "name": "PreferenceSwitcher", + "mount": "PreferenceSwitcher", + "category": "navigation", + "purpose": "Accessible theme, accent color, and language preference controls.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "themeLabel", + "type": "string", + "required": false, + "default": "\"Theme\"" + }, + { + "name": "colorLabel", + "type": "string", + "required": false, + "default": "\"Accent color\"" + }, + { + "name": "languageLabel", + "type": "string", + "required": false, + "default": "\"Language\"" + }, + { + "name": "languages", + "type": "string", + "required": false, + "default": "[" + }, + { + "name": "colors", + "type": "string", + "required": false, + "default": "[" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["theme", "color", "language"], + "source": "components/PreferenceSwitcher.wrn" + }, + { + "name": "Progress", + "mount": "Progress", + "category": "base", + "purpose": "Theme-aware, responsive progress component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Progress\"" + }, + { + "name": "value", + "type": "number", + "required": false, + "default": "50" + }, + { + "name": "max", + "type": "number", + "required": false, + "default": "100" + }, + { + "name": "showValue", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/progress.wrn" + }, + { + "name": "PublicPageShell", + "mount": "PublicPageShell", + "category": "layout", + "purpose": "Consistent structural wrapper for public-facing pages.", + "props": [ + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"full\"" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "headerOffset", + "type": "string", + "required": false, + "default": "\"none\"" + }, + { + "name": "background", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "overflow", + "type": "string", + "required": false, + "default": "\"clip\"" + }, + { + "name": "minHeight", + "type": "string", + "required": false, + "default": "\"screen\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["before", "default", "after"], + "events": [], + "source": "components/PublicPageShell.wrn" + }, + { + "name": "Radio", + "mount": "Radio", + "category": "forms", + "purpose": "Theme-aware, responsive radio component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Radio\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"on\"" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "checked", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"vertical\"" + }, + { + "name": "card", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "rightAligned", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "list", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "invalid"], + "source": "components/Radio.wrn" + }, + { + "name": "RangeSlider", + "mount": "RangeSlider", + "category": "forms", + "purpose": "Theme-aware, responsive range slider component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Range\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "value", + "type": "number", + "required": false, + "default": "50" + }, + { + "name": "min", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "max", + "type": "number", + "required": false, + "default": "100" + }, + { + "name": "step", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "showValue", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showBounds", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showSteps", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "marks", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur"], + "source": "components/RangeSlider.wrn" + }, + { + "name": "Rating", + "mount": "Rating", + "category": "base", + "purpose": "Theme-aware, responsive rating component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Rating\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change"], + "source": "components/Rating.wrn" + }, + { + "name": "Scrollspy", + "mount": "Scrollspy", + "category": "navigation", + "purpose": "Theme-aware, responsive scrollspy component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Scrollspy\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["change"], + "source": "components/Scrollspy.wrn" + }, + { + "name": "SearchBox", + "mount": "SearchBox", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive search box component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Search Box\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"search\"" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/SearchBox.wrn" + }, + { + "name": "Section", + "mount": "Section", + "category": "layout", + "purpose": "Theme-aware page section with consistent spacing, width, background, and border controls.", + "props": [ + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "spacing", + "type": "string", + "required": false, + "default": "\"lg\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "borderTop", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "borderBottom", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Section.wrn" + }, + { + "name": "SectionHeader", + "mount": "SectionHeader", + "category": "layout", + "purpose": "Reusable accessible section heading with eyebrow, title, description, icon, and actions.", + "props": [ + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "headingLevel", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"3xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["icon", "default", "actions"], + "events": [], + "source": "components/SectionHeader.wrn" + }, + { + "name": "Select", + "mount": "Select", + "category": "forms", + "purpose": "Theme-aware, responsive select component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Select\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "values", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Select an option\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "open", "close", "invalid"], + "source": "components/Select.wrn" + }, + { + "name": "Sidebar", + "mount": "Sidebar", + "category": "navigation", + "purpose": "Theme-aware, responsive sidebar component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Sidebar\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "mobileLabel", + "type": "string", + "required": false, + "default": "\"Open navigation\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["toggle", "open", "close", "select"], + "source": "components/Sidebar.wrn" + }, + { + "name": "Skeleton", + "mount": "Skeleton", + "category": "base", + "purpose": "Theme-aware, responsive skeleton component.", + "props": [ + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Loading\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "lines", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/skeleton.wrn" + }, + { + "name": "Spinner", + "mount": "Spinner", + "category": "base", + "purpose": "Theme-aware, responsive spinner component.", + "props": [ + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Loading\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "lines", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/spinner.wrn" + }, + { + "name": "SplitHero", + "mount": "SplitHero", + "category": "blocks", + "purpose": "Two-column hero with configurable content and visual placement.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"A better digital experience\"" + }, + { + "name": "highlight", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "visualPosition", + "type": "string", + "required": false, + "default": "\"right\"" + }, + { + "name": "reverse", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "ratio", + "type": "string", + "required": false, + "default": "\"balanced\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "trustItems", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["actions", "trust", "default", "visual"], + "events": [], + "source": "components/SplitHero.wrn" + }, + { + "name": "StatsBar", + "mount": "StatsBar", + "category": "blocks", + "purpose": "Compact responsive statistics strip.", + "props": [ + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "4" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "dividers", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "icons", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"raised\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/StatsBar.wrn" + }, + { + "name": "Stepper", + "mount": "Stepper", + "category": "navigation", + "purpose": "Theme-aware, responsive stepper component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Stepper\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["change", "previous", "next", "complete"], + "source": "components/Stepper.wrn" + }, + { + "name": "StrongPassword", + "mount": "StrongPassword", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive strong password component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Password\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"password\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Create a strong password\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"new-password\"" + }, + { + "name": "minLength", + "type": "number", + "required": false, + "default": "8" + }, + { + "name": "specialCharactersSet", + "type": "string", + "required": false, + "default": "\"!@#$%^&*()_+-=[]{}|;:,.<>?\"" + }, + { + "name": "requireLowercase", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "requireUppercase", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "requireNumber", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "requireSpecialCharacter", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showRequirements", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "presentation", + "type": "string", + "required": false, + "default": "\"inline\"" + }, + { + "name": "hintText", + "type": "string", + "required": false, + "default": "\"Use a unique password you do not use elsewhere.\"" + }, + { + "name": "emptyLabel", + "type": "string", + "required": false, + "default": "\"Enter a password\"" + }, + { + "name": "weakLabel", + "type": "string", + "required": false, + "default": "\"Weak\"" + }, + { + "name": "fairLabel", + "type": "string", + "required": false, + "default": "\"Fair\"" + }, + { + "name": "goodLabel", + "type": "string", + "required": false, + "default": "\"Good\"" + }, + { + "name": "strongLabel", + "type": "string", + "required": false, + "default": "\"Strong\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "strength"], + "source": "components/StrongPassword.wrn" + }, + { + "name": "StyledIcon", + "mount": "StyledIcon", + "category": "base", + "purpose": "Theme-aware, responsive styled icon component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Styled Icon\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/StyledIcon.wrn" + }, + { + "name": "Switch", + "mount": "Switch", + "category": "forms", + "purpose": "Theme-aware, responsive switch component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Switch\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"on\"" + }, + { + "name": "checked", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur"], + "source": "components/Switch.wrn" + }, + { + "name": "Table", + "mount": "Table", + "category": "tables", + "purpose": "Theme-aware, responsive table component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "caption", + "type": "string", + "required": false, + "default": "\"Table\"" + }, + { + "name": "columns", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "rows", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "striped", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["sort", "select", "rowClick"], + "source": "components/table.wrn" + }, + { + "name": "Tabs", + "mount": "Tabs", + "category": "navigation", + "purpose": "Theme-aware, responsive tabs component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Tabs\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Tabs.wrn" + }, + { + "name": "Textarea", + "mount": "Textarea", + "category": "forms", + "purpose": "Theme-aware, responsive textarea component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Textarea\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "rows", + "type": "number", + "required": false, + "default": "5" + }, + { + "name": "resize", + "type": "string", + "required": false, + "default": "\"vertical\"" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "minlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "maxlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "invalid"], + "source": "components/Textarea.wrn" + }, + { + "name": "TextLink", + "mount": "TextLink", + "category": "layout", + "purpose": "Styled inline action link with icons, arrows, external state, and disabled handling.", + "props": [ + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Learn more\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"#\"" + }, + { + "name": "target", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "rel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "external", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "showArrow", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "underline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["click", "focus", "blur"], + "source": "components/TextLink.wrn" + }, + { + "name": "Timeline", + "mount": "Timeline", + "category": "base", + "purpose": "Theme-aware, responsive timeline component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Timeline\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Timeline.wrn" + }, + { + "name": "TimePicker", + "mount": "TimePicker", + "category": "forms", + "purpose": "Theme-aware, responsive time picker component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Time\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--clock-3]\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"end\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "format", + "type": "string", + "required": false, + "default": "\"24\"" + }, + { + "name": "minuteStep", + "type": "number", + "required": false, + "default": "5" + }, + { + "name": "hours", + "type": "string", + "required": false, + "default": "[\"00\", \"01\", \"02\", \"03\", \"04\", \"05\", \"06\", \"07\", \"08\", \"09\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"20\", \"21\", \"22\", \"23\"]" + }, + { + "name": "minutes", + "type": "string", + "required": false, + "default": "[\"00\", \"05\", \"10\", \"15\", \"20\", \"25\", \"30\", \"35\", \"40\", \"45\", \"50\", \"55\"]" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "open", "close", "invalid"], + "source": "components/TimePicker.wrn" + }, + { + "name": "Toast", + "mount": "Toast", + "category": "base", + "purpose": "Theme-aware, responsive toast component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Toast\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["dismiss", "action"], + "source": "components/Toast.wrn" + }, + { + "name": "ToastNotifications", + "mount": "ToastNotifications", + "category": "integrations", + "purpose": "Theme-aware, responsive toast notifications component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Toast Notifications\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["add", "dismiss", "clear", "action"], + "source": "components/ToastNotifications.wrn" + }, + { + "name": "ToggleCount", + "mount": "ToggleCount", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive toggle count component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"segmented\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"billing-cycle\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"monthly\"" + }, + { + "name": "firstValue", + "type": "string", + "required": false, + "default": "\"monthly\"" + }, + { + "name": "firstLabel", + "type": "string", + "required": false, + "default": "\"Monthly\"" + }, + { + "name": "secondValue", + "type": "string", + "required": false, + "default": "\"annual\"" + }, + { + "name": "secondLabel", + "type": "string", + "required": false, + "default": "\"Annual\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Billing frequency\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "currency", + "type": "string", + "required": false, + "default": "\"$\"" + }, + { + "name": "suffix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "firstValueKey", + "type": "string", + "required": false, + "default": "\"monthly\"" + }, + { + "name": "secondValueKey", + "type": "string", + "required": false, + "default": "\"annual\"" + }, + { + "name": "emptyValue", + "type": "string", + "required": false, + "default": "\"—\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"end\"" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "animate", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "animationDuration", + "type": "number", + "required": false, + "default": "450" + }, + { + "name": "animationSteps", + "type": "number", + "required": false, + "default": "18" + } + ], + "slots": [], + "events": ["change", "toggle"], + "source": "components/ToggleCount.wrn" + }, + { + "name": "TogglePassword", + "mount": "TogglePassword", + "category": "advanced-forms", + "purpose": "Accessible password field with optional show and hide controls.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Password\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"password\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Enter your password\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"current-password\"" + }, + { + "name": "minlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "maxlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "pattern", + "type": "string", + "required": false, + "default": "\"(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}\"" + }, + { + "name": "fields", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "visible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "toggleable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "toggleMode", + "type": "string", + "required": false, + "default": "\"button\"" + }, + { + "name": "checkboxLabel", + "type": "string", + "required": false, + "default": "\"Show password\"" + }, + { + "name": "showLabel", + "type": "string", + "required": false, + "default": "\"Show password\"" + }, + { + "name": "hideLabel", + "type": "string", + "required": false, + "default": "\"Hide password\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "toggle"], + "source": "components/TogglePassword.wrn" + }, + { + "name": "Tooltip", + "mount": "Tooltip", + "category": "overlays", + "purpose": "Theme-aware, responsive tooltip component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Tooltip\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close"], + "source": "components/tooltip.wrn" + }, + { + "name": "TreeView", + "mount": "TreeView", + "category": "base", + "purpose": "Theme-aware, responsive tree view component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Tree View\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "toggle", "expand", "collapse"], + "source": "components/TreeView.wrn" + }, + { + "name": "Typography", + "mount": "Typography", + "category": "layout", + "purpose": "Theme-aware, responsive typography component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Typography.wrn" + }, + { + "name": "WysiwygEditor", + "mount": "WysiwygEditor", + "category": "integrations", + "purpose": "Theme-aware, responsive wysiwyg editor component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Wysiwyg Editor\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change", "focus", "blur"], + "source": "components/WysiwygEditor.wrn" + } + ] +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/progress.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/progress.wrn new file mode 100644 index 00000000..dea093ca --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/progress.wrn @@ -0,0 +1,17 @@ +component Progress { + props { + size = "default" + color = "primary" + label = "Progress" + value = 50 + max = 100 + showValue = true + class = "" + } + view { +
+
{label}{#if showValue}{value}%{/if}
+ +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/skeleton.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/skeleton.wrn new file mode 100644 index 00000000..3adaf9fd --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/skeleton.wrn @@ -0,0 +1,14 @@ +component Skeleton { + props { + color = "primary" + label = "Loading" + size = "md" + lines = 3 + class = "" + } + view { +
+ {#if "Skeleton" === "Skeleton"}{#each Array(lines).fill(0) as line}{/each}{:else}{/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/spinner.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/spinner.wrn new file mode 100644 index 00000000..bd607734 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/spinner.wrn @@ -0,0 +1,14 @@ +component Spinner { + props { + color = "primary" + label = "Loading" + size = "md" + lines = 3 + class = "" + } + view { +
+ {#if "Spinner" === "Skeleton"}{#each Array(lines).fill(0) as line}{/each}{:else}{/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/table.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/table.wrn new file mode 100644 index 00000000..1f5dc29f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/table.wrn @@ -0,0 +1,17 @@ +component Table { + props { + @event sort = function + @event select = function + @event rowClick = function + size = "default" + color = "primary" + caption = "Table" + columns = [] + rows = [] + striped = true + class = "" + } + view { +
{#each columns as column}{/each}{#each rows as row}{#each columns as column}{/each}{/each}
{caption}
{column.label}
{row[column.key]}
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/tooltip.wrn b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/tooltip.wrn new file mode 100644 index 00000000..240da14c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/tooltip.wrn @@ -0,0 +1,21 @@ +component Tooltip { + props { + @event open = function + @event close = function + size = "default" + color = "primary" + title = "Tooltip" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { +
+
{title}
+ {#if description}

{description}

{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ui.test.ts b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ui.test.ts new file mode 100644 index 00000000..19a8b144 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-2026-07-30T12-50-29-410Z/ui.test.ts @@ -0,0 +1,2438 @@ +import { expect, test } from "bun:test"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import { compileWireFile } from "../../compiler/src/index.ts"; +import { mountHtml, renderComponent } from "../../test/src/index.ts"; +import { uiComponentNames, uiComponentsDir, uiComponentPath, uiCss } from "../src/index.ts"; + +test("bundled UI assets are discoverable and readable", () => { + expect(uiComponentNames()).toContain("Button"); + expect(uiComponentNames()).toContain("Accordion"); + expect(uiComponentNames()).toContain("DataTable"); + expect(uiComponentNames()).toContain("WysiwygEditor"); + expect(readFileSync(uiComponentPath("Button"), "utf8")).toContain("component Button"); + expect(uiCss()).toContain("--wire-"); +}); + +test("generated component reference documents every bundled component and its props", () => { + const reference = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-reference.json"), "utf8"), + ) as { count: number; components: Array<{ name: string; props: Array<{ name: string }> }> }; + const catalog = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-catalog.json"), "utf8"), + ) as { components: Array<{ name: string }> }; + expect(reference.count).toBe(uiComponentNames().length); + expect(reference.count).toBe(108); + expect(reference.components.map((component) => component.name)).toEqual( + expect.arrayContaining(uiComponentNames()), + ); + expect(catalog.components.map((component) => component.name).sort()).toEqual( + uiComponentNames().sort(), + ); + expect(reference.components.find((component) => component.name === "Button")?.props).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "label" }), + expect.objectContaining({ name: "as" }), + ]), + ); + expect( + reference.components + .find((component) => component.name === "PinInput") + ?.props.find((prop) => prop.name === "length"), + ).toEqual(expect.objectContaining({ default: "4" })); +}); + +test("interactive components expose their must-have public event contracts", () => { + const reference = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-reference.json"), "utf8"), + ) as { components: Array<{ name: string; events: string[] }> }; + const eventsByComponent = new Map( + reference.components.map((component) => [component.name, component.events]), + ); + const requiredEvents: Record = { + Button: ["click", "focus", "blur"], + Input: ["input", "change", "focus", "blur", "invalid"], + Select: ["input", "change", "open", "close"], + Checkbox: ["input", "change", "focus", "blur", "invalid"], + ColorPicker: ["input", "change", "focus", "blur"], + FileInput: ["input", "change", "focus", "blur", "select", "clear", "invalid"], + InputGroup: ["input", "change", "focus", "blur", "submit", "action"], + Radio: ["input", "change", "focus", "blur", "invalid"], + RangeSlider: ["input", "change", "focus", "blur"], + Switch: ["input", "change", "focus", "blur"], + Textarea: ["input", "change", "focus", "blur", "invalid"], + TimePicker: ["input", "change", "focus", "blur", "open", "close", "invalid"], + Accordion: ["change", "open", "close"], + Modal: ["open", "close", "cancel", "confirm"], + DataTable: ["sort", "select", "change", "rowClick", "pageChange"], + FileUpload: ["select", "upload", "progress", "success", "error", "cancel", "remove"], + WysiwygEditor: ["input", "change", "focus", "blur"], + }; + + for (const [component, events] of Object.entries(requiredEvents)) { + expect(eventsByComponent.get(component)).toEqual(expect.arrayContaining(events)); + } +}); + +test("component reference contains only explicitly declared public events", () => { + const reference = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-reference.json"), "utf8"), + ) as { components: Array<{ name: string; events: string[] }> }; + + for (const component of reference.components) { + const source = readFileSync(uiComponentPath(component.name), "utf8"); + const declaredEvents = [ + ...source.matchAll(/@event\s+([A-Za-z][A-Za-z0-9_]*)\s*=\s*function/g), + ].map((match) => match[1]); + expect(component.events).toEqual([...new Set(declaredEvents)]); + } +}); + +test("bundled components do not duplicate another component implementation", () => { + const implementations = new Map(); + + for (const name of uiComponentNames()) { + const source = readFileSync(uiComponentPath(name), "utf8") + .replace(/^component\s+[A-Za-z0-9_]+/, "component __NAME__") + .replace(/\r\n/g, "\n") + .trim(); + expect(implementations.get(source)).toBeUndefined(); + implementations.set(source, name); + } +}); + +test("removed duplicate aliases have valid canonical migration targets", () => { + const migration = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-migrations.json"), "utf8"), + ) as { removedCount: number; replacements: Record }; + const names = new Set(uiComponentNames()); + + expect(Object.keys(migration.replacements)).toHaveLength(migration.removedCount); + expect(migration.removedCount).toBe(0); + for (const [removed, replacement] of Object.entries(migration.replacements)) { + expect(names.has(removed)).toBe(false); + expect(names.has(replacement)).toBe(true); + } +}); + +test("screenshot-directed canonical components are bundled", () => { + const required = [ + "Container", + "Columns", + "Grid", + "Typography", + "Button", + "Accordion", + "Alert", + "Avatar", + "Card", + "Carousel", + "DatePicker", + "Progress", + "Spinner", + "Timeline", + "Navbar", + "Tabs", + "Sidebar", + "Breadcrumb", + "Pagination", + "Stepper", + "Input", + "Textarea", + "Checkbox", + "Radio", + "Switch", + "Select", + "ComboBox", + "TimePicker", + "Modal", + "Drawer", + "Popover", + "Tooltip", + "Table", + "DataTable", + "Chart", + "FileUpload", + "Map", + "WysiwygEditor", + ]; + + expect(uiComponentNames()).toEqual(expect.arrayContaining(required)); +}); + +test("navbar supports brands, nested menus, actions, utility slots, and public events", () => { + const source = readFileSync(uiComponentPath("Navbar"), "utf8"); + expect(source).toContain('slot name="topbar"'); + expect(source).toContain('slot name="actions"'); + expect(source).toContain("brand = {}"); + expect(source).toContain("actions = []"); + expect(source).toContain("openOnHover = false"); + expect(source).toContain('maxWidth = "full"'); + expect(source).toContain("item.children"); + expect(source).toContain("child.children"); + expect(source).toContain("wire-navbar__dropdown--{item.type || 'dropdown'}"); + for (const event of ["toggle", "open", "close", "select", "action"]) { + expect(source).toContain(`@event ${event} = function`); + } +}); + +test("auth form uses package schemas, disables native validation, and renders a full-width submit control", async () => { + const source = readFileSync(uiComponentPath("AuthForm"), "utf8"); + expect(source).toContain('return "auth-login"'); + expect(source).toContain('data-schema="{schemaName()}"'); + expect(source).toContain('data-wrnexus-runtime="auth"'); + expect(source).toContain('novalidate="true"'); + expect(source).toContain('fullWidth="true"'); + + const html = await renderComponent(source, { mode: "sign-in" }); + expect(html).toContain('data-schema="auth-login"'); + expect(html).toContain('data-wrnexus-runtime="auth"'); + expect(html).toContain("novalidate"); + expect(html).toContain("wire-auth-form__submit"); + expect(html).toContain('fullWidth="true"'); +}); + +test("footer supports typed entries, responsive columns, pre/post slots, and events", () => { + const source = readFileSync(uiComponentPath("Footer"), "utf8"); + expect(source).toContain('slot name="pre-footer"'); + expect(source).toContain('slot name="post-footer"'); + expect(source).toContain('slot name="copyright-left"'); + expect(source).toContain('slot name="copyright-right"'); + expect(source).toContain('item.type === "header"'); + expect(source).toContain("wire-footer--columns-{columns}"); + expect(source).toContain("@event select = function"); + expect(source).toContain("@event action = function"); +}); + +test("navbar renders a brand, nested dropdowns, mega groups, and actions", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Navbar"), "utf8"), { + brand: { + label: "Police Management System", + description: "Public portal", + href: "/", + }, + items: [ + { + label: "Services", + type: "dropdown", + children: [{ label: "Reports", href: "/reports" }], + }, + { + label: "Safety", + type: "mega", + columns: 2, + children: [ + { + label: "Resources", + children: [{ label: "Guidance", href: "/guidance" }], + }, + ], + }, + ], + actions: [{ label: "Sign in", href: "/login", variant: "primary" }], + }); + + expect(html).toContain("Police Management System"); + expect(html).toContain("Public portal"); + expect(html).toContain("Reports"); + expect(html).toContain("Guidance"); + expect(html).toContain("wire-navbar__dropdown--mega"); + expect(html).toContain("data-wrn-navbar"); + expect(html).toContain('name="wire-navbar-menu"'); + expect(html).toContain("Sign in"); +}); + +test("navbar closes sibling menus and menus close after an outside pointer press", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Navbar"), "utf8"), { + items: [ + { label: "Services", children: [{ label: "Reports", href: "/reports" }] }, + { label: "Safety", children: [{ label: "Guidance", href: "/guidance" }] }, + ], + }); + const dom = mountHtml(html); + const menus = Array.from(dom.querySelectorAll(".wire-navbar__dropdown")) as HTMLDetailsElement[]; + + menus[0].open = true; + menus[0].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("toggle", { bubbles: false }), + ); + menus[1].open = true; + menus[1].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("toggle", { bubbles: false }), + ); + expect(menus[0].open).toBe(false); + expect(menus[1].open).toBe(true); + + dom.document.body.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("pointerdown", { bubbles: true }), + ); + expect(menus[1].open).toBe(false); +}); + +test("navbar optionally opens menus on hover and renders full-width mode", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Navbar"), "utf8"), { + openOnHover: true, + maxWidth: "full", + items: [{ label: "Services", children: [{ label: "Reports", href: "/reports" }] }], + }); + const dom = mountHtml(html); + const navbar = dom.querySelector("[data-wrn-navbar]"); + const menu = dom.querySelector(".wire-navbar__dropdown") as HTMLDetailsElement; + + expect(navbar?.classList.contains("wire-navbar--width-full")).toBe(true); + expect(navbar?.getAttribute("data-open-on-hover")).toBe("true"); + menu.dispatchEvent(new (dom.window as { Event: typeof Event }).Event("pointerenter")); + expect(menu.open).toBe(true); + menu.dispatchEvent(new (dom.window as { Event: typeof Event }).Event("pointerleave")); + expect(menu.open).toBe(true); + await new Promise((resolve) => setTimeout(resolve, 280)); + expect(menu.open).toBe(false); +}); + +test("navbar hover menu stays open while the pointer crosses into its panel", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Navbar"), "utf8"), { + openOnHover: true, + items: [{ label: "Services", children: [{ label: "Reports", href: "/reports" }] }], + }); + const dom = mountHtml(html); + const menu = dom.querySelector(".wire-navbar__dropdown") as HTMLDetailsElement; + const panel = dom.querySelector(".wire-navbar__panel") as HTMLElement; + const DomEvent = (dom.window as { Event: typeof Event }).Event; + + menu.dispatchEvent(new DomEvent("pointerenter")); + menu.dispatchEvent(new DomEvent("pointerleave")); + panel.dispatchEvent(new DomEvent("pointerenter", { bubbles: true })); + await new Promise((resolve) => setTimeout(resolve, 280)); + + expect(menu.open).toBe(true); +}); + +test("preference switcher keeps only one popover open and closes outside", async () => { + const html = await renderComponent( + readFileSync(uiComponentPath("PreferenceSwitcher"), "utf8"), + {}, + ); + const dom = mountHtml(html); + const menus = Array.from(dom.querySelectorAll(".wire-preferences__menu")) as HTMLDetailsElement[]; + const DomEvent = (dom.window as { Event: typeof Event }).Event; + + menus[0].open = true; + menus[0].dispatchEvent(new DomEvent("toggle")); + menus[1].open = true; + menus[1].dispatchEvent(new DomEvent("toggle")); + expect(menus[0].open).toBe(false); + expect(menus[1].open).toBe(true); + + dom.document.body.dispatchEvent(new DomEvent("pointerdown", { bubbles: true })); + expect(menus[1].open).toBe(false); +}); + +test("sidebar renders compact grouped submenu navigation and a mobile drawer trigger", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Sidebar"), "utf8"), { + label: "Operations", + orientation: "vertical", + items: [ + { label: "Dashboard", href: "/dashboard", value: "dashboard" }, + { + label: "Case management", + children: [ + { label: "Assigned cases", href: "/cases", value: "cases" }, + { label: "Evidence", href: "/evidence", value: "evidence" }, + ], + }, + ], + }); + + expect(html).toContain("wire-sidebar-toggle"); + expect(html).toContain("wire-sidebar-backdrop"); + expect(html).toContain("wire-sidebar-group"); + expect(html).toContain("Assigned cases"); + expect(html).toContain("Evidence"); +}); + +test("dropdown renders slotted account triggers, menu structure, and public events", async () => { + const source = readFileSync(uiComponentPath("Dropdown"), "utf8"); + const html = await renderComponent(source, { + label: "Account menu", + items: [ + { type: "header", label: "Account" }, + { label: "Profile", href: "/profile", icon: "icon-[lucide--user]" }, + { type: "divider" }, + { label: "Sign out", href: "/logout", danger: true }, + ], + }); + + expect(source).toContain('slot name="trigger"'); + expect(source).toContain("@event select = function"); + expect(html).toContain("wire-dropdown__panel"); + expect(html).toContain("Profile"); + expect(html).toContain("wire-dropdown__item--danger"); +}); + +test("footer renders header and link entries with the requested column count", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Footer"), "utf8"), { + columns: 4, + items: [ + { type: "header", label: "Support" }, + { type: "link", label: "Contact", href: "/contact" }, + ], + copyright: "Public service platform", + }); + + expect(html).toContain("wire-footer--columns-4"); + expect(html).toContain("wire-footer__column"); + expect(html).toContain("wire-footer__column-links"); + expect(html).toContain("wire-footer__heading"); + expect(html).toContain("Support"); + expect(html).toContain('href="/contact"'); + expect(html).toContain("Public service platform"); +}); + +test("component-system CSS includes responsive, theme-token, focus, and reduced-motion rules", () => { + const css = uiCss(); + expect(css).toContain("@media (max-width: 768px)"); + expect(css).toContain("@media (max-width: 480px)"); + expect(css).toContain("@media (prefers-reduced-motion: reduce)"); + expect(css).toContain(":focus-visible"); + expect(css).toContain("var(--wire-color-surface)"); + expect(css).toContain("min-height: 44px"); + expect(css).toContain("--wire-motion-base"); + expect(css).toContain("--wire-ease-emphasized"); + expect(css).toContain("@keyframes wire-component-enter"); + expect(css).toContain("@keyframes wire-dialog-enter"); + expect(css).toContain("@media (hover: hover) and (pointer: fine)"); + expect(css).toContain("--color-violet-600: var(--wire-color-primary)"); + expect(css).toContain("--color-blue-600: var(--wire-color-info)"); + expect(css).toContain("--color-red-600: var(--wire-color-danger)"); + expect(css).toMatch(/:root\s*\{[^}]*--color-violet-600: var\(--wire-color-primary\)/s); + expect(css).toContain(".wire-bg-primary"); + expect(css).toContain(".wire-text-muted"); + expect(css).toContain(".wire-visually-hidden"); + expect(css).toContain(".wire-next--field"); + expect(css).toContain(".wire-next--table"); + expect(css).toContain('[data-show="false"]'); + expect(css).toContain("display: none !important"); + expect(css).toMatch( + /\.wire-navbar__brand-copy strong\s*\{[^}]*font-size: 0\.9rem;[^}]*font-weight: 600;/s, + ); + expect(css).toMatch( + /\.wire-navbar__menu-link,[\s\S]*?font-size: 0\.8125rem;[\s\S]*?font-weight: 500;/, + ); + expect(css).toMatch( + /\.wire-footer__heading\s*\{[^}]*font-size: 0\.8125rem;[^}]*font-weight: 600;/s, + ); + expect(css).toMatch(/\.wire-footer__link\s*\{[^}]*font-size: 0\.8125rem;[^}]*font-weight: 400;/s); +}); + +test("component boundaries have no default margins and expose the canonical class prop", () => { + for (const name of uiComponentNames()) { + const source = readFileSync(uiComponentPath(name), "utf8"); + const root = source.match(/view\s*\{\s*<[A-Za-z][^>]*>/)?.[0] ?? ""; + const classes = root.match(/\bclass="([^"]*)"/)?.[1]?.split(/\s+/) ?? []; + expect(classes.filter((token) => /^-?m[trblxy]?-/.test(token))).toEqual([]); + expect(source).toMatch(/^\s*class\s*(?::[^=\r\n]+)?=/m); + expect(source).not.toMatch(/^\s*className\s*(?::[^=\r\n]+)?=/m); + expect(root).toContain("{class}"); + } +}); + +test("every component exposes universal color and size configuration", () => { + for (const name of uiComponentNames()) { + const source = readFileSync(uiComponentPath(name), "utf8"); + expect(source).toMatch(/^\s+color\s*=/m); + expect(source).toMatch(/^\s+size\s*=/m); + } +}); + +// test("component markup keeps user-facing content and data behind props", () => { +// for (const name of uiComponentNames()) { +// const source = readFileSync(uiComponentPath(name), "utf8"); +// const view = source.slice(source.indexOf("view {")); +// const literalText = [...view.matchAll(/>([^<>{}]*[A-Za-z][^<>{}]*) match[1].trim()) +// .filter(Boolean); +// const literalAccessibleText = [ +// ...view.matchAll(/\b(?:aria-label|title|placeholder|alt)="([^"{}]*[A-Za-z][^"{}]*)"/g), +// ]; +// const literalDataAttributes = [ +// ...view.matchAll(/\b(?:href|src|action|value)="([^"{}]+)"/g), +// ].filter((match) => !/^(?:true|false|on)$/.test(match[1])); + +// expect(literalText).toEqual([]); +// expect(literalAccessibleText).toEqual([]); +// expect(literalDataAttributes).toEqual([]); +// } +// }); + +test("layout boundaries do not add default padding", () => { + for (const name of ["Container", "Columns", "Grid", "LayoutSplitter", "Typography"]) { + const source = readFileSync(uiComponentPath(name), "utf8"); + const root = source.match(/view\s*\{\s*<[A-Za-z][^>]*>/)?.[0] ?? ""; + const classes = root.match(/\bclass="([^"]*)"/)?.[1]?.split(/\s+/) ?? []; + expect(classes.filter((token) => /^p[trblxy]?-/.test(token))).toEqual([]); + } +}); + +test("every bundled UI component compiles", () => { + for (const name of uiComponentNames()) { + const path = uiComponentPath(name); + expect(() => compileWireFile(readFileSync(path, "utf8"), path)).not.toThrow(); + } +}); + +test("icon buttons expose their accessible label as a hover and focus tooltip", () => { + const button = readFileSync(uiComponentPath("Button"), "utf8"); + expect(button).toContain('class="wire-btn__tooltip"'); + expect(button).toContain("{ariaLabel || label}"); + expect(uiCss()).toContain(".wire-btn:hover > .wire-btn__tooltip"); + expect(uiCss()).toContain(".wire-btn:focus-visible > .wire-btn__tooltip"); +}); + +test("button links navigate by default and only download when the native attribute is passed", () => { + const button = readFileSync(uiComponentPath("Button"), "utf8"); + expect(button).not.toMatch(/^\s+download\s*=/m); + expect(button).not.toContain('download="{download}"'); + expect(button).toContain("{...attrs}"); +}); + +test("button group renders connected actions and emits select and change events", async () => { + const source = readFileSync(uiComponentPath("ButtonGroup"), "utf8"); + const html = await renderComponent(source, { + items: [ + { label: "Profile", value: "profile" }, + { label: "Settings", value: "settings" }, + { label: "Messages", value: "messages", disabled: true }, + ], + value: "profile", + selectable: true, + size: "sm", + variant: "outline", + ariaLabel: "Account views", + }); + const dom = mountHtml(html); + const group = dom.querySelector(".wire-next--button-group") as HTMLElement; + const buttons = [...dom.querySelectorAll(".wire-next--button-group > button")]; + const events: Array<{ name: string; detail: unknown }> = []; + + for (const name of ["select", "change"]) { + group.addEventListener(name, (event) => + events.push({ name, detail: (event as CustomEvent).detail }), + ); + } + + expect(group.getAttribute("role")).toBe("group"); + expect(group.getAttribute("aria-label")).toBe("Account views"); + expect(group.getAttribute("data-size")).toBe("sm"); + expect(buttons).toHaveLength(3); + expect(buttons[0]?.getAttribute("aria-pressed")).toBe("true"); + expect(buttons[2]?.hasAttribute("disabled")).toBe(true); + + (buttons[1] as HTMLButtonElement).click(); + + expect(buttons[0]?.getAttribute("aria-pressed")).toBe("false"); + expect(buttons[1]?.getAttribute("aria-pressed")).toBe("true"); + expect(events.map((event) => event.name)).toEqual(["select", "change"]); + expect((events[1]?.detail as { value: string }).value).toBe("settings"); + expect((events[1]?.detail as { previousValue: string }).previousValue).toBe("profile"); +}); + +test("button group supports vertical, responsive, detached, and toolbar layouts", async () => { + const source = readFileSync(uiComponentPath("ButtonGroup"), "utf8"); + const html = await renderComponent(source, { + items: [{ label: "Bold", icon: "icon-[lucide--bold]" }], + orientation: "vertical", + responsive: true, + attached: false, + toolbar: true, + ariaLabel: "Formatting", + }); + const dom = mountHtml(html); + const group = dom.querySelector(".wire-next--button-group") as HTMLElement; + + expect(group.getAttribute("role")).toBe("toolbar"); + expect(group.getAttribute("aria-orientation")).toBe("vertical"); + expect(group.getAttribute("data-responsive")).toBe("true"); + expect(group.getAttribute("data-attached")).toBe("false"); + expect(group.querySelector('[class*="icon-[lucide--bold]"]')).not.toBeNull(); + + const css = uiCss(); + expect(css).toContain('.wire-next--button-group[data-orientation="vertical"]'); + expect(css).toContain('.wire-next--button-group[data-responsive="true"]'); + expect(css).toContain('.wire-next--button-group[data-attached="false"]'); +}); + +test("every bundled UI component forwards undeclared native attributes", () => { + for (const name of uiComponentNames()) { + const path = uiComponentPath(name); + const output = compileWireFile(readFileSync(path, "utf8"), path); + expect(output).toContain("${__wireSpreadAttrs(__attrs)}"); + } +}); + +test("accordion coordinates single-open sections and emits open, close, and change events", async () => { + const source = readFileSync(uiComponentPath("Accordion"), "utf8"); + const html = await renderComponent(source, { + id: "faq", + defaultOpen: ["first"], + items: [ + { value: "first", label: "First", content: "First content" }, + { value: "second", label: "Second", content: "Second content" }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-accordion]") as HTMLElement; + const events: string[] = []; + for (const name of ["open", "close", "change"]) { + root.addEventListener(name, () => events.push(name)); + } + + expect(dom.querySelector("#faq-trigger-0")?.getAttribute("aria-expanded")).toBe("true"); + expect(dom.querySelector("#faq-panel-0")?.getAttribute("aria-hidden")).toBe("false"); + + (dom.querySelector("#faq-trigger-1") as HTMLButtonElement).click(); + + expect(dom.querySelector("#faq-trigger-0")?.getAttribute("aria-expanded")).toBe("false"); + expect(dom.querySelector("#faq-trigger-1")?.getAttribute("aria-expanded")).toBe("true"); + expect(events).toEqual(["open", "change"]); + + (dom.querySelector("#faq-trigger-1") as HTMLButtonElement).click(); + expect(dom.querySelector("#faq-trigger-1")?.getAttribute("aria-expanded")).toBe("false"); + expect(events).toEqual(["open", "change", "close", "change"]); +}); + +test("accordion supports always-open, nested, and disabled sections", async () => { + const source = readFileSync(uiComponentPath("Accordion"), "utf8"); + const html = await renderComponent(source, { + id: "nested-faq", + alwaysOpen: true, + defaultOpen: ["first", "first.child"], + items: [ + { + value: "first", + label: "First", + content: "First content", + children: [{ value: "child", label: "Child", content: "Child content" }], + }, + { value: "second", label: "Second", content: "Second content" }, + { value: "third", label: "Third", content: "Third content", disabled: true }, + ], + }); + const dom = mountHtml(html); + + expect(dom.querySelector("#nested-faq-trigger-0")?.getAttribute("aria-expanded")).toBe("true"); + expect(dom.querySelector("#nested-faq-trigger-0-0")?.getAttribute("aria-expanded")).toBe("true"); + + (dom.querySelector("#nested-faq-trigger-1") as HTMLButtonElement).click(); + expect(dom.querySelector("#nested-faq-trigger-0")?.getAttribute("aria-expanded")).toBe("true"); + expect(dom.querySelector("#nested-faq-trigger-1")?.getAttribute("aria-expanded")).toBe("true"); + expect((dom.querySelector("#nested-faq-trigger-2") as HTMLButtonElement).disabled).toBe(true); +}); + +test("accordion chevrons use a consistent icon instead of a font glyph", () => { + const source = readFileSync(uiComponentPath("Accordion"), "utf8"); + + expect(source).toContain("icon-[lucide--chevron-down]"); + expect(source).not.toContain('return "⌄"'); +}); + +test("alert renders structured content, lists, actions, and accessible semantics", async () => { + const source = readFileSync(uiComponentPath("Alert"), "utf8"); + const html = await renderComponent(source, { + title: "Cannot save changes", + description: "Review the following fields.", + color: "danger", + variant: "soft", + showIcon: true, + items: [{ label: "Email is required" }, { label: "Phone number is invalid" }], + actions: [{ label: "Review form", href: "#form" }], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-alert]") as HTMLElement; + let detail: Record | undefined; + root.addEventListener("action", (event) => { + detail = (event as unknown as CustomEvent>).detail; + }); + + expect(root.getAttribute("role")).toBe("alert"); + expect(root.getAttribute("aria-live")).toBe("polite"); + expect(root.dataset.color).toBe("danger"); + expect(dom.querySelectorAll(".wire-next__alert-body li").map((node) => node.textContent)).toEqual( + ["Email is required", "Phone number is invalid"], + ); + + (dom.querySelector(".wire-next__alert-actions a") as HTMLAnchorElement).click(); + expect(detail).toMatchObject({ + component: "Alert", + action: { label: "Review form", href: "#form" }, + }); +}); + +test("dismissible alert hides itself and emits dismiss details", async () => { + const source = readFileSync(uiComponentPath("Alert"), "utf8"); + const html = await renderComponent(source, { + title: "Update available", + description: "Install the latest version.", + dismissible: true, + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-alert]") as HTMLElement; + let dismissed = false; + root.addEventListener("dismiss", () => { + dismissed = true; + }); + + (dom.querySelector(".wire-next__alert-dismiss") as HTMLButtonElement).click(); + + expect(dismissed).toBe(true); + expect(root.getAttribute("aria-hidden")).toBe("true"); + expect(root.style.display).toBe("none"); +}); + +test("solid alert palettes preserve readable foregrounds and compact inline layout", () => { + const css = uiCss(); + + expect(css).toContain('.wire-next--alert[data-color="secondary"]'); + expect(css).toContain("--wire-alert-color: #737373"); + expect(css).toContain( + ".wire-next--alert-compact:not(:has(.wire-next__alert-icon)):not(:has(.wire-next__alert-dismiss))", + ); + expect(css).toContain(".wire-next--alert-compact .wire-next__alert-body > p"); + expect(css).toContain("color: currentColor"); +}); + +test("alert exposes configurable radius and elevation treatments", async () => { + const source = readFileSync(uiComponentPath("Alert"), "utf8"); + const html = await renderComponent(source, { + title: "Elevated alert", + radius: "xl", + shadow: "lg", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-alert]") as HTMLElement; + const css = uiCss(); + + expect(root.dataset.radius).toBe("xl"); + expect(root.dataset.shadow).toBe("lg"); + expect(css).toContain('.wire-next--alert[data-radius="xl"]'); + expect(css).toContain('.wire-next--alert[data-shadow="lg"]'); + expect(css).toContain("border-radius: calc(var(--wire-radius, 0.75rem) * 1.75)"); + expect(css).toContain("0 20px 48px color-mix(in srgb, #000 24%, transparent)"); +}); + +test("avatar renders images, fallbacks, presence, badges, tooltips, and media copy", async () => { + const source = readFileSync(uiComponentPath("Avatar"), "utf8"); + const imageHtml = await renderComponent(source, { + src: "/avatar.jpg", + alt: "Avery Chen", + shape: "rounded", + statusPosition: "top", + status: "online", + statusLabel: "Online", + tooltip: "Avery Chen · Online", + }); + const imageDom = mountHtml(imageHtml); + const imageRoot = imageDom.querySelector("[data-wrn-avatar]") as HTMLElement; + + expect(imageRoot.querySelector('img[alt="Avery Chen"]')).not.toBeNull(); + expect(imageRoot.querySelector('[data-status="online"]')?.getAttribute("aria-label")).toBe( + "Online", + ); + expect(imageRoot.querySelector('[role="tooltip"]')?.textContent).toContain("Avery Chen"); + + const initialsDom = mountHtml( + await renderComponent(source, { + initials: "MW", + color: "success", + badgeIcon: "icon-[lucide--message-square]", + badgeLabel: "Messaging account", + name: "Mark Wanner", + description: "mark@example.com", + }), + ); + expect(initialsDom.querySelector(".wire-next__avatar-initials")?.textContent).toBe("MW"); + expect(initialsDom.querySelector(".wire-next__avatar-badge")?.getAttribute("aria-label")).toBe( + "Messaging account", + ); + expect(initialsDom.querySelector(".wire-next__avatar-copy")?.textContent).toContain( + "mark@example.com", + ); + + const placeholderDom = mountHtml(await renderComponent(source, { size: "sm" })); + expect(placeholderDom.querySelector(".wire-next__avatar-placeholder")).not.toBeNull(); + expect(source).not.toContain("items ="); + expect(uiCss()).toContain('.wire-next__avatar-wrap[data-shape="rounded"]'); +}); + +test("avatar group limits members and opens an accessible overflow menu", async () => { + const source = readFileSync(uiComponentPath("AvatarGroup"), "utf8"); + const html = await renderComponent(source, { + maxVisible: 2, + borderColor: "#2583ff", + items: [ + { src: "/one.svg", name: "One" }, + { initials: "TW", name: "Two" }, + { initials: "TH", name: "Three" }, + { initials: "FO", name: "Four" }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-avatar-group]") as HTMLElement; + const button = root.querySelector( + ".wire-next__avatar-group-overflow-button", + ) as HTMLButtonElement; + let eventDetail: { open: boolean; hiddenCount: number } | undefined; + root.addEventListener("overflow", (event) => { + eventDetail = (event as CustomEvent).detail; + }); + + expect(root.querySelectorAll(".wire-next__avatar-group-member")).toHaveLength(2); + expect(button.textContent?.trim()).toBe("+2"); + expect(button.getAttribute("aria-expanded")).toBe("false"); + expect(root.getAttribute("style")).toContain("#2583ff"); + expect(root.querySelector(".wire-next__avatar-group-menu")?.getAttribute("data-show")).toBe( + "false", + ); + + button.click(); + + expect( + dom.querySelector(".wire-next__avatar-group-overflow-button")?.getAttribute("aria-expanded"), + ).toBe("true"); + expect(dom.querySelectorAll('[role="menuitem"]')).toHaveLength(2); + expect(dom.querySelector(".wire-next__avatar-group-menu")?.getAttribute("data-show")).toBe( + "true", + ); + expect(eventDetail).toEqual(expect.objectContaining({ open: true, hiddenCount: 2 })); + expect(uiCss()).toContain('.wire-next--avatar-group[data-layout="grid"]'); +}); + +test("badge supports rich content, anchored placement, animation, and dismissal", async () => { + const source = readFileSync(uiComponentPath("Badge"), "utf8"); + const html = await renderComponent(source, { + label: "Christina", + color: "success", + variant: "soft", + icon: "icon-[lucide--circle-check]", + dot: true, + avatarSrc: "/avatar.svg", + avatarAlt: "Christina", + dismissible: true, + animated: true, + anchorIcon: "icon-[lucide--bell]", + anchorLabelText: "Open notifications", + placement: "top-right", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-badge]") as HTMLElement; + let dismissed = ""; + root.addEventListener("dismiss", (event) => { + dismissed = (event as CustomEvent).detail.label; + }); + + expect(root.dataset.placement).toBe("top-right"); + expect(root.querySelector(".wire-next__badge-anchor")?.getAttribute("aria-label")).toBe( + "Open notifications", + ); + expect(root.querySelector('img[alt="Christina"]')).not.toBeNull(); + expect(root.querySelector(".wire-next__badge-dot")).not.toBeNull(); + expect(root.querySelector(".wire-next__badge-ping")).not.toBeNull(); + + (root.querySelector(".wire-next__badge-dismiss") as HTMLButtonElement).click(); + + expect(dom.querySelector("[data-wrn-badge]")?.getAttribute("data-show")).toBe("false"); + expect(dismissed).toBe("Christina"); + expect(source).not.toContain("items ="); + expect(uiCss()).toContain("@keyframes wire-badge-ping"); +}); + +test("blockquote renders semantic quote and citation content", async () => { + const source = readFileSync(uiComponentPath("Blockquote"), "utf8"); + const html = await renderComponent(source, { + quote: "Design is intelligence made visible.", + citation: "Alina Wheeler", + citationTitle: "Author, Designing Brand Identity", + citationUrl: "https://example.com/source", + avatarSrc: "/authors/alina.jpg", + avatarAlt: "Alina Wheeler", + size: "lg", + color: "info", + align: "center", + }); + const dom = mountHtml(html); + const figure = dom.querySelector("figure") as HTMLElement; + const quote = figure.querySelector("blockquote"); + const citation = figure.querySelector("figcaption"); + + expect(figure.getAttribute("data-size")).toBe("lg"); + expect(figure.getAttribute("data-color")).toBe("info"); + expect(figure.getAttribute("data-align")).toBe("center"); + expect(quote?.getAttribute("cite")).toBe("https://example.com/source"); + expect(quote?.textContent).toContain("Design is intelligence made visible."); + expect(quote?.querySelector('[aria-hidden="true"]')?.textContent).toBe("“"); + expect(citation?.querySelector("cite a")?.textContent).toBe("Alina Wheeler"); + expect(citation?.textContent).toContain("Author, Designing Brand Identity"); + expect(citation?.querySelector("img")?.getAttribute("alt")).toBe("Alina Wheeler"); +}); + +test("blockquote supports bordered, right-aligned, non-italic, and slotted quotes", async () => { + const source = readFileSync(uiComponentPath("Blockquote"), "utf8"); + const html = await renderComponent(source, { + quote: "", + variant: "bordered", + align: "right", + italic: false, + quoteMark: false, + }); + const dom = mountHtml(html); + const figure = dom.querySelector("figure") as HTMLElement; + + expect(figure.getAttribute("data-variant")).toBe("bordered"); + expect(figure.getAttribute("data-align")).toBe("right"); + expect(figure.getAttribute("data-italic")).toBe("false"); + expect(figure.querySelector(".wire-next__blockquote-mark")).toBeNull(); + expect(source).toContain(""); + + const css = uiCss(); + expect(css).toContain('.wire-next--blockquote[data-variant="bordered"]'); + expect(css).toContain('.wire-next--blockquote[data-align="center"]'); + expect(css).toContain("--wire-blockquote-font-size"); +}); + +test("card renders structured media, header, body, action, and footer content", async () => { + const source = readFileSync(uiComponentPath("Card"), "utf8"); + const html = await renderComponent(source, { + title: "Release notes", + subtitle: "Version 2.4", + description: "A structured card description.", + header: "Featured", + footer: "Updated today", + imageSrc: "/release.jpg", + imageAlt: "Release preview", + actionLabel: "Read more", + actionHref: "/releases/2-4", + size: "lg", + color: "info", + }); + const dom = mountHtml(html); + const card = dom.querySelector(".wire-next--card") as HTMLElement; + + expect(card.getAttribute("data-size")).toBe("lg"); + expect(card.getAttribute("data-color")).toBe("info"); + expect(card.querySelector("article")).not.toBeNull(); + expect(card.querySelector("header")?.textContent).toContain("Featured"); + expect(card.querySelector("img")?.getAttribute("alt")).toBe("Release preview"); + expect(card.querySelector("h3")?.textContent).toBe("Release notes"); + expect(card.querySelector(".wire-next__card-subtitle")?.textContent).toBe("Version 2.4"); + expect(card.querySelector(".wire-next__card-action")?.getAttribute("href")).toBe("/releases/2-4"); + expect(card.querySelector("footer")?.textContent).toContain("Updated today"); +}); + +test("card navigation, header actions, and dismissal emit public events", async () => { + const source = readFileSync(uiComponentPath("Card"), "utf8"); + const html = await renderComponent(source, { + title: "Account", + header: "Card actions", + navigation: [ + { label: "Profile", value: "profile" }, + { label: "Security", value: "security" }, + ], + activeNav: "profile", + headerActions: [{ label: "Refresh", icon: "icon-[lucide--refresh-cw]" }], + dismissible: true, + }); + const dom = mountHtml(html); + const card = dom.querySelector(".wire-next--card") as HTMLElement; + const events: string[] = []; + + for (const name of ["navigate", "action", "dismiss"]) { + card.addEventListener(name, () => events.push(name)); + } + + (dom.querySelectorAll(".wire-next__card-tabs button")[1] as HTMLButtonElement).click(); + (dom.querySelector(".wire-next__card-header-actions button") as HTMLButtonElement).click(); + (dom.querySelectorAll(".wire-next__card-header-actions button")[1] as HTMLButtonElement).click(); + + expect(events).toEqual(["navigate", "action", "dismiss"]); + expect(dom.querySelector(".wire-next__card-panel")?.hasAttribute("hidden")).toBe(true); +}); + +test("card supports overlays, horizontal media, groups, alerts, empty and scrolling panels", async () => { + const source = readFileSync(uiComponentPath("Card"), "utf8"); + const overlay = mountHtml( + await renderComponent(source, { + title: "Overlay", + description: "Overlay copy", + imageSrc: "/overlay.jpg", + imagePosition: "overlay", + }), + ); + const group = mountHtml( + await renderComponent(source, { + items: [ + { title: "First", description: "First card" }, + { title: "Second", description: "Second card" }, + ], + }), + ); + const panel = mountHtml( + await renderComponent(source, { + title: "", + alertTitle: "Attention", + alertDescription: "Review this state.", + empty: true, + scrollable: true, + maxHeight: "12rem", + }), + ); + + expect(overlay.querySelector(".wire-next__card-overlay")).not.toBeNull(); + expect(group.querySelectorAll(".wire-next__card-group > article")).toHaveLength(2); + expect(panel.querySelector(".wire-next__card-alert")?.getAttribute("role")).toBe("status"); + expect(panel.querySelector(".wire-next__card-empty")?.textContent).toContain("No data to show"); + expect(panel.querySelector(".wire-next__card-body")?.getAttribute("data-scrollable")).toBe( + "true", + ); + + const css = uiCss(); + expect(css).toContain('.wire-next--card[data-layout="horizontal"]'); + expect(css).toContain('.wire-next--card[data-hover="image"]'); + expect(css).toContain(".wire-next__card-group"); + expect(css).toContain(".wire-next__card-navigation-select"); + expect(css).toContain("aspect-ratio: 16 / 9"); + expect(css).toContain("rgb(2 6 23 / 0.86)"); +}); + +test("chat bubble renders conversations, avatars, metadata, links, and public events", async () => { + const source = readFileSync(uiComponentPath("ChatBubble"), "utf8"); + const events: string[] = []; + const dom = mountHtml( + await renderComponent(source, { + ariaLabel: "Support conversation", + oneSided: true, + showAvatars: true, + showMetadata: true, + items: [ + { + direction: "incoming", + author: "Support", + avatarFallback: "SP", + title: "How can we help?", + text: "Choose a guide.", + bullets: ["Installation", "Components"], + links: [{ label: "Installation guide", href: "/installation" }], + status: "Sent", + timestamp: "10:32", + }, + { + direction: "outgoing", + text: "Please retry.", + status: "Not sent", + statusTone: "danger", + action: "retry", + actionLabel: "Retry", + }, + ], + }), + ); + + const root = dom.querySelector(".wire-next--chat-bubble") as HTMLElement; + for (const [name, label] of [ + ["messageClick", "message"], + ["avatarClick", "avatar"], + ["linkClick", "link"], + ["action", "action"], + ]) { + root.addEventListener(name, () => events.push(label)); + } + expect(root.getAttribute("role")).toBe("log"); + expect(root.getAttribute("aria-label")).toBe("Support conversation"); + expect(root.dataset.oneSided).toBe("true"); + expect(dom.querySelectorAll(".wire-next__chat-message")).toHaveLength(2); + expect(dom.querySelectorAll(".wire-next__chat-content li")).toHaveLength(2); + expect(dom.querySelector(".wire-next__chat-meta[data-tone='danger']")).not.toBeNull(); + expect(uiCss()).toContain("color: var(--wire-color-primary-contrast, #fff)"); + + (dom.querySelector(".wire-next__chat-content") as HTMLElement).click(); + (dom.querySelector(".wire-next__chat-avatar") as HTMLButtonElement).click(); + (dom.querySelector(".wire-next__chat-content a") as HTMLAnchorElement).click(); + (dom.querySelector(".wire-next__chat-meta button") as HTMLButtonElement).click(); + expect(events).toEqual(["message", "avatar", "link", "action"]); +}); + +test("collapse toggles accessible panels and emits open, close, and toggle events", async () => { + const source = readFileSync(uiComponentPath("Collapse"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + ariaLabel: "Product details", + initialOpenIndexes: [0], + items: [ + { + id: "product-details", + label: "Expand", + closeLabel: "Collapse", + title: "Details", + content: "Additional product information.", + }, + ], + }), + ); + const root = dom.querySelector(".wire-next--collapse") as HTMLElement; + const trigger = dom.querySelector(".wire-next__collapse-trigger") as HTMLButtonElement; + const panel = dom.querySelector(".wire-next__collapse-panel") as HTMLElement; + const events: string[] = []; + for (const name of ["open", "close", "toggle"]) { + root.addEventListener(name, () => events.push(name)); + } + + expect(root.getAttribute("aria-label")).toBe("Product details"); + expect(trigger.getAttribute("aria-expanded")).toBe("true"); + expect(trigger.getAttribute("aria-controls")).toBe("product-details"); + expect(panel.dataset.open).toBe("true"); + expect(panel.getAttribute("aria-hidden")).toBe("false"); + expect(uiCss()).toContain("max-height: 40rem"); + expect(trigger.textContent).toContain("Collapse"); + + trigger.click(); + expect(trigger.getAttribute("aria-expanded")).toBe("false"); + expect(panel.dataset.open).toBe("false"); + expect(panel.getAttribute("aria-hidden")).toBe("true"); + expect(events).toEqual(["close", "toggle"]); + + trigger.click(); + expect(panel.dataset.open).toBe("true"); + expect(events).toEqual(["close", "toggle", "open", "toggle"]); +}); + +test("collapse supports inline read-more and single or multiple open panels", async () => { + const source = readFileSync(uiComponentPath("Collapse"), "utf8"); + const items = [ + { id: "first-collapse", label: "Read more", preview: "First preview", content: "First" }, + { id: "second-collapse", label: "Read more", preview: "Second preview", content: "Second" }, + ]; + const single = mountHtml(await renderComponent(source, { mode: "inline", items })); + const singleTriggers = single.querySelectorAll( + ".wire-next__collapse-trigger", + ) as HTMLButtonElement[]; + singleTriggers[0]?.click(); + singleTriggers[1]?.click(); + expect(singleTriggers[0]?.getAttribute("aria-expanded")).toBe("false"); + expect(singleTriggers[1]?.getAttribute("aria-expanded")).toBe("true"); + expect(single.querySelectorAll(".wire-next__collapse-preview")).toHaveLength(2); + + const multiple = mountHtml(await renderComponent(source, { multiple: true, items })); + const multipleTriggers = multiple.querySelectorAll( + ".wire-next__collapse-trigger", + ) as HTMLButtonElement[]; + multipleTriggers[0]?.click(); + multipleTriggers[1]?.click(); + expect(multipleTriggers[0]?.getAttribute("aria-expanded")).toBe("true"); + expect(multipleTriggers[1]?.getAttribute("aria-expanded")).toBe("true"); +}); + +test("basic form fields expose shared labels, variants, states, hints, values, and validation targets", async () => { + const { checkField } = await import("../../validation/src/index.ts"); + const validation = checkField( + { + type: "string", + optional: false, + trim: true, + rules: [{ kind: "email", message: "Enter a valid email address." }], + }, + "not-an-email", + ); + expect(validation.error).toBe("Enter a valid email address."); + + const source = readFileSync(uiComponentPath("Input"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "account-email", + name: "email", + label: "Email address", + placeholder: "you@example.com", + value: "not-an-email", + type: "email", + variant: "floating", + icon: "icon-[lucide--mail]", + iconPosition: "end", + helperText: "Used for account notices.", + cornerHint: "Required", + error: validation.error, + inline: true, + required: true, + }), + ); + const root = dom.querySelector(".wire-next--input") as HTMLElement; + const input = dom.querySelector("input") as HTMLInputElement; + expect(root.dataset.variant).toBe("floating"); + expect(root.dataset.inline).toBe("true"); + expect(root.dataset.invalid).toBe("true"); + expect(input.id).toBe("account-email"); + expect(input.name).toBe("email"); + expect(input.value).toBe("not-an-email"); + expect(input.getAttribute("aria-invalid")).toBe("true"); + expect(dom.querySelector("[data-error='email']")?.textContent).toContain( + "Enter a valid email address.", + ); + expect(dom.querySelector(".wire-next__field-hint")?.textContent).toContain("Required"); + expect(dom.querySelector(".wire-next__field-icon")).not.toBeNull(); + + const emitted: string[] = []; + for (const name of ["input", "change", "focus", "blur", "keydown", "keyup"]) { + root.addEventListener(name, () => emitted.push(name)); + } + input.dispatchEvent(new (dom.window as any).Event("input", { bubbles: true })); + input.dispatchEvent(new (dom.window as any).Event("change", { bubbles: true })); + input.dispatchEvent(new (dom.window as any).Event("focus", { bubbles: true })); + input.dispatchEvent(new (dom.window as any).Event("blur", { bubbles: true })); + input.dispatchEvent( + new (dom.window as any).KeyboardEvent("keydown", { key: "Enter", bubbles: true }), + ); + input.dispatchEvent( + new (dom.window as any).KeyboardEvent("keyup", { key: "Enter", bubbles: true }), + ); + expect(emitted).toEqual(["input", "change", "focus", "blur", "keydown", "keyup"]); +}); + +test("all basic form components render values and their must-have interaction events", async () => { + const components = [ + "Checkbox", + "ColorPicker", + "FileInput", + "Input", + "InputGroup", + "Radio", + "RangeSlider", + "Select", + "Switch", + "Textarea", + "TimePicker", + ]; + for (const component of components) { + const source = readFileSync(uiComponentPath(component), "utf8"); + const props: Record = { + id: `${component}-field`, + name: `${component}Value`, + label: `${component} label`, + helperText: "Helper text", + cornerHint: "Optional", + error: "", + inline: true, + readonly: true, + disabled: false, + value: component === "RangeSlider" ? 40 : "value", + options: [{ label: "Value", value: "value" }], + }; + const dom = mountHtml(await renderComponent(source, props)); + const control = dom.querySelector("input, textarea, select") as HTMLElement | null; + expect(control).not.toBeNull(); + expect(control?.getAttribute("name")).toBe(`${component}Value`); + expect(dom.querySelector(".wire-next__field-help")?.textContent).toContain("Helper text"); + expect(dom.querySelector(`[data-error="${component}Value"]`)).not.toBeNull(); + } +}); + +test("radio renders passed options in group, card, list, alignment, and description layouts", async () => { + const source = readFileSync(uiComponentPath("Radio"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "plan", + name: "plan", + label: "Choose a plan", + value: "professional", + orientation: "horizontal", + card: true, + list: true, + rightAligned: true, + options: [ + { label: "Starter", value: "starter", description: "For individuals." }, + { label: "Professional", value: "professional", description: "For teams." }, + { label: "Enterprise", value: "enterprise", disabled: true }, + ], + }), + ); + + const root = dom.querySelector(".wire-next--radio-field") as HTMLElement; + const controls = [...dom.querySelectorAll('input[type="radio"]')] as HTMLInputElement[]; + expect(root.dataset.orientation).toBe("horizontal"); + expect(root.dataset.card).toBe("true"); + expect(root.dataset.list).toBe("true"); + expect(root.dataset.rightAligned).toBe("true"); + expect(controls).toHaveLength(3); + expect(controls[1]?.checked).toBe(true); + expect(controls[2]?.disabled).toBe(true); + expect(dom.querySelectorAll(".wire-next__choice-copy small")).toHaveLength(2); +}); + +test("checkbox renders passed values in group, card, list, alignment, description, and mixed layouts", async () => { + const source = readFileSync(uiComponentPath("Checkbox"), "utf8"); + const group = mountHtml( + await renderComponent(source, { + id: "notifications", + name: "notifications", + label: "Notification preferences", + values: ["account"], + orientation: "horizontal", + card: true, + list: true, + rightAligned: true, + options: [ + { label: "Product", value: "product", description: "Product news." }, + { label: "Account", value: "account", description: "Security alerts." }, + { label: "Partners", value: "partners", disabled: true }, + ], + }), + ); + const controls = [...group.querySelectorAll('input[type="checkbox"]')] as HTMLInputElement[]; + expect(group.querySelector(".wire-next--checkbox-field")?.getAttribute("data-orientation")).toBe( + "horizontal", + ); + expect(controls).toHaveLength(3); + expect(controls[1]?.checked).toBe(true); + expect(controls[2]?.disabled).toBe(true); + expect(group.querySelectorAll(".wire-next__choice-copy small")).toHaveLength(2); + + const mixed = mountHtml( + await renderComponent(source, { id: "mixed", name: "mixed", indeterminate: true }), + ); + expect(mixed.querySelector("input")?.getAttribute("aria-checked")).toBe("mixed"); +}); + +test("range slider exposes value, minimum, maximum, step, bounds, and optional marks", async () => { + const source = readFileSync(uiComponentPath("RangeSlider"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "volume", + name: "volume", + value: 50, + min: 0, + max: 100, + step: 25, + showBounds: true, + showSteps: true, + marks: [ + { value: 0, label: "Minimum" }, + { value: 50, label: "Middle" }, + { value: 100, label: "Maximum" }, + ], + }), + ); + + const control = dom.querySelector('input[type="number"]') as HTMLInputElement; + const slider = dom.querySelector('[role="slider"]') as HTMLElement; + expect(control.min).toBe("0"); + expect(control.max).toBe("100"); + expect(control.step).toBe("25"); + expect(slider.getAttribute("aria-valuenow")).toBe("50"); + expect(dom.querySelector(".wire-next__range-bounds")?.textContent).toContain("Step 25"); + expect(dom.querySelectorAll(".wire-next__slider-marks button")).toHaveLength(3); + expect(slider.getAttribute("tabindex")).toBe("0"); + expect(source).toContain('sourceEvent.key === "ArrowRight"'); + const increase = dom.querySelector('[aria-label="Increase Range"]') as HTMLButtonElement; + increase.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector('[role="slider"]')?.getAttribute("aria-valuenow")).toBe("75"); + dom + .querySelector('[role="slider"]') + ?.dispatchEvent( + new (dom.window as any).KeyboardEvent("keydown", { key: "ArrowRight", bubbles: true }), + ); + expect(dom.querySelector('[role="slider"]')?.getAttribute("aria-valuenow")).toBe("100"); + const middleMark = dom.querySelectorAll( + ".wire-next__slider-marks button", + )[1] as HTMLButtonElement; + middleMark.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector('[role="slider"]')?.getAttribute("aria-valuenow")).toBe("50"); + expect((dom.querySelector('input[type="number"]') as HTMLInputElement).value).toBe("50"); +}); + +test("date picker renders a custom calendar trigger with accessible field state and events", async () => { + const source = readFileSync(uiComponentPath("DatePicker"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "start-date", + name: "startDate", + label: "Start date", + value: "2026-07-28", + min: "2026-01-01", + max: "2026-12-31", + helperText: "Use your local date.", + cornerHint: "Required", + required: true, + }), + ); + const input = dom.querySelector("input") as HTMLInputElement; + expect(input.type).toBe("text"); + expect(input.required).toBe(true); + expect(dom.querySelector("label")?.getAttribute("for")).toBe("start-date"); + expect(dom.querySelector('button[aria-haspopup="dialog"]')).not.toBeNull(); + expect(source).not.toContain('type="{type}"'); + expect(source).toContain("months ="); + expect(dom.querySelector(".wire-next__field-help")?.textContent).toContain("local date"); + const trigger = dom.querySelector('button[aria-haspopup="dialog"]') as HTMLButtonElement; + expect(dom.querySelector(".wire-next--date-picker")?.getAttribute("data-expanded")).toBe("false"); + trigger.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector(".wire-next--date-picker")?.getAttribute("data-expanded")).toBe("true"); + expect(dom.querySelector('button[aria-haspopup="dialog"]')?.getAttribute("aria-expanded")).toBe( + "true", + ); + expect(dom.querySelectorAll(".wire-next__calendar-grid button")).toHaveLength(31); + const fifteenth = dom.querySelectorAll( + ".wire-next__calendar-grid button", + )[14] as HTMLButtonElement; + fifteenth.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(input.value).toBe("2026-07-15"); + expect(dom.querySelector(".wire-next__date-trigger span")?.textContent).toBe("2026-07-15"); +}); + +test("time picker uses a custom reactive panel instead of the browser time control", async () => { + const source = readFileSync(uiComponentPath("TimePicker"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "meeting-time", + name: "meetingTime", + value: "13:30", + format: "12", + minuteStep: 15, + }), + ); + expect(source).not.toContain('type="time"'); + const trigger = dom.querySelector(".wire-next__time-trigger") as HTMLButtonElement; + expect(trigger.textContent).toContain("13:30"); + trigger.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector(".wire-next--time-picker")?.getAttribute("data-expanded")).toBe("true"); + expect(dom.querySelectorAll(".wire-next__time-options").length).toBe(2); + expect(dom.querySelectorAll(".wire-next__time-options button")).toHaveLength(36); + const nine = [...dom.querySelectorAll(".wire-next__time-options button")].find( + (button) => button.textContent?.trim() === "09", + ) as HTMLButtonElement; + nine.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect((dom.querySelector('input[name="meetingTime"]') as HTMLInputElement).value).toBe("09:30"); + expect(dom.querySelector(".wire-next__time-trigger span")?.textContent).toBe("09:30"); +}); + +test("file upload progress reacts to cancel, retry, and complete actions", async () => { + const source = readFileSync(uiComponentPath("FileUploadProgress"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + fileName: "design-system.zip", + fileSize: "20 MB", + uploadedSize: "10 MB", + value: 50, + max: 100, + status: "uploading", + }), + ); + expect(dom.querySelector(".wire-next--file-upload-progress")?.getAttribute("data-status")).toBe( + "uploading", + ); + expect(dom.querySelector(".wire-next__row")?.textContent).toContain("design-system.zip"); + const buttons = dom.querySelectorAll(".wire-next__upload-actions button") as HTMLButtonElement[]; + buttons[0]?.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector(".wire-next--file-upload-progress")?.getAttribute("data-status")).toBe( + "cancelled", + ); +}); + +test("carousel renders accessible slides, pagination, counter, and navigation events", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const html = await renderComponent(source, { + ariaLabel: "Featured stories", + showPagination: true, + showCounter: true, + items: [ + { title: "First story", description: "First description" }, + { title: "Second story", description: "Second description" }, + { title: "Third story", description: "Third description" }, + ], + }); + const dom = mountHtml(html); + const carousel = dom.querySelector(".wire-next--carousel") as HTMLElement; + const scopeRoot = dom.querySelector("[data-wrn-scope]") as HTMLElement; + const encodedScope = scopeRoot.getAttribute("data-wrn-scope") ?? ""; + const hydratedScope = JSON.parse(Buffer.from(encodedScope, "base64").toString("utf8")) as { + items: Array<{ title: string }>; + }; + const events: string[] = []; + for (const name of ["change", "next", "previous"]) { + carousel.addEventListener(name, () => events.push(name)); + } + + expect(carousel.getAttribute("role")).toBe("region"); + expect(carousel.getAttribute("aria-roledescription")).toBe("carousel"); + expect(carousel.getAttribute("aria-label")).toBe("Featured stories"); + expect(hydratedScope.items.map((item) => item.title)).toEqual([ + "First story", + "Second story", + "Third story", + ]); + expect(dom.querySelectorAll('[aria-roledescription="slide"]')).toHaveLength(3); + expect(dom.querySelectorAll(".wire-next__carousel-pagination button")).toHaveLength(3); + expect(dom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("1 / 3"); + + (dom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement).click(); + expect(dom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("2 / 3"); + expect(events).toEqual(["change", "next"]); + + (dom.querySelector('[aria-label="Previous slide"]') as HTMLButtonElement).click(); + expect(events).toEqual(["change", "next", "change", "previous"]); +}); + +test("carousel supports RTL, multiple slides, dragging, snap, and thumbnail layouts", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const items = [{ title: "First" }, { title: "Second" }, { title: "Third" }, { title: "Fourth" }]; + const html = await renderComponent(source, { + items, + slidesPerView: 3, + isRTL: true, + isDraggable: true, + isAutoHeight: true, + thumbnails: "vertical", + }); + const dom = mountHtml(html); + const carousel = dom.querySelector(".wire-next--carousel") as HTMLElement; + const track = dom.querySelector(".wire-next__carousel-track") as HTMLElement; + + expect(carousel.getAttribute("dir")).toBe("rtl"); + expect(carousel.dataset.draggable).toBe("true"); + expect(carousel.dataset.autoHeight).toBe("true"); + expect(carousel.dataset.thumbnails).toBe("vertical"); + expect(track.getAttribute("style")).toContain("--wire-carousel-per-view: 3"); + expect(dom.querySelectorAll(".wire-next__carousel-thumbnails button")).toHaveLength(4); + + const snapHtml = await renderComponent(source, { + items, + isSnap: true, + isDraggable: true, + }); + const snapDom = mountHtml(snapHtml); + const snapRoot = snapDom.querySelector(".wire-next--carousel") as HTMLElement; + expect(snapRoot.dataset.snap).toBe("true"); + expect(snapRoot.dataset.draggable).toBe("false"); + + const css = uiCss(); + expect(css).toContain('.wire-next--carousel[data-rtl="true"]'); + expect(css).toContain('.wire-next--carousel[data-snap="true"]'); + expect(css).toContain('.wire-next--carousel[data-thumbnails="vertical"]'); + expect(css).toContain("user-select: none"); + expect(css).toContain('.wire-next--carousel[data-centered="true"] .wire-next__carousel-track'); +}); + +test("carousel autoplay timers are available in the browser reactive runtime", async () => { + const { getReactiveRuntime } = await import("../../csr/src/index.ts"); + const runtime = getReactiveRuntime(); + expect(runtime).toContain('name === "setInterval"'); + expect(runtime).toContain('name === "clearInterval"'); +}); + +test("carousel snap controls scroll and multiple slides stop at the last full group", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const items = [ + { title: "First" }, + { title: "Second" }, + { title: "Third" }, + { title: "Fourth" }, + { title: "Fifth" }, + { title: "Sixth" }, + ]; + const snapDom = mountHtml( + await renderComponent(source, { + items, + isSnap: true, + showPagination: true, + }), + ); + const viewport = snapDom.querySelector(".wire-next__carousel-viewport") as HTMLElement & { + scrollTo: (options: ScrollToOptions) => void; + }; + let scrollLeft: number | undefined; + viewport.scrollTo = (options: ScrollToOptions | number) => { + scrollLeft = typeof options === "number" ? options : options.left; + }; + ( + snapDom.querySelectorAll(".wire-next__carousel-pagination button")[1] as HTMLButtonElement + ).click(); + expect(scrollLeft).toBeDefined(); + const snapNext = snapDom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement; + for (let index = 0; index < items.length; index++) snapNext.click(); + const paginationButtons = snapDom.querySelectorAll(".wire-next__carousel-pagination button"); + expect(paginationButtons[items.length - 1]?.getAttribute("aria-current")).toBe("true"); + expect(snapNext.disabled).toBe(true); + + const multipleDom = mountHtml( + await renderComponent(source, { + items, + slidesPerView: 3, + showCounter: true, + }), + ); + const next = multipleDom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement; + for (let index = 0; index < 6; index++) next.click(); + expect(multipleDom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("4 / 6"); + expect(next.disabled).toBe(true); +}); + +test("carousel centers the last slide and auto-scrolls thumbnail rails", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const items = [{ title: "First" }, { title: "Second" }, { title: "Third" }, { title: "Fourth" }]; + const centeredDom = mountHtml( + await renderComponent(source, { + items, + isCentered: true, + showCounter: true, + }), + ); + const centeredNext = centeredDom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement; + for (let index = 0; index < items.length; index++) centeredNext.click(); + expect(centeredDom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("4 / 4"); + expect(centeredNext.disabled).toBe(true); + + for (const thumbnails of ["horizontal", "vertical"]) { + const dom = mountHtml(await renderComponent(source, { items, thumbnails })); + const buttons = dom.querySelectorAll( + ".wire-next__carousel-thumbnails button", + ) as HTMLButtonElement[]; + let scrolled = false; + const rail = buttons[1]?.parentElement as HTMLElement & { + scrollTo: (options: ScrollToOptions) => void; + }; + rail.scrollTo = () => { + scrolled = true; + }; + (dom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement).click(); + expect(scrolled).toBe(true); + } +}); + +test("carousel autoplay wraps to the first slide", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const html = await renderComponent(source, { + isAutoPlay: true, + autoplayInterval: 1000, + activeIndex: 2, + showCounter: true, + items: [{ title: "First" }, { title: "Second" }, { title: "Third" }], + }); + const dom = mountHtml(html); + await Bun.sleep(1100); + expect(dom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("1 / 3"); + dom + .querySelector(".wire-next--carousel") + ?.dispatchEvent(new (dom.window as any).Event("mouseenter", { bubbles: true })); +}); + +test("input number increments, decrements, applies steps, and respects limits", async () => { + const source = readFileSync(uiComponentPath("InputNumber"), "utf8"); + const html = await renderComponent(source, { + name: "quantity", + value: 1, + min: 0, + max: 5, + step: 2, + }); + const dom = mountHtml(html); + const input = () => dom.querySelector('input[name="quantity"]') as HTMLInputElement; + const decrement = () => dom.querySelector('[aria-label="Decrease value"]') as HTMLButtonElement; + const increment = () => dom.querySelector('[aria-label="Increase value"]') as HTMLButtonElement; + + expect(input().value).toBe("1"); + + increment().click(); + expect(input().value).toBe("3"); + + increment().click(); + expect(input().value).toBe("5"); + expect(increment().disabled).toBe(true); + + decrement().click(); + expect(input().value).toBe("3"); + + decrement().click(); + decrement().click(); + expect(input().value).toBe("0"); + expect(decrement().disabled).toBe(true); +}); + +test("advanced select opens, filters, and selects without reactive handler errors", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const html = await renderComponent(source, { + name: "team", + options: [ + { value: "design", label: "Design" }, + { value: "engineering", label: "Engineering" }, + { value: "growth", label: "Growth" }, + ], + }); + const dom = mountHtml(html); + const trigger = dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement; + expect(trigger).not.toBeNull(); + trigger.click(); + expect( + dom.querySelector(".wire-next--advanced-select")?.classList.contains("wire-next--open"), + ).toBe(true); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("true"); + expect(dom.querySelector('[role="listbox"]')).not.toBeNull(); + const search = dom.querySelector(".wire-next__select-search input") as HTMLInputElement; + search.value = "engine"; + search.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + const options = dom.querySelectorAll(".wire-next__select-option") as HTMLButtonElement[]; + expect(options.filter((option) => option.style.display !== "none")).toHaveLength(1); + options.find((option) => option.style.display !== "none")?.click(); + expect(dom.querySelector(".wire-next__select-value > span")?.textContent).toBe("Engineering"); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("false"); + (dom.querySelector(".wire-next__clear-select") as HTMLButtonElement).click(); + expect(dom.querySelector(".wire-next__select-value > span")?.textContent).toBe( + "Select an option", + ); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe(""); +}); + +test("advanced select clears, restores its placeholder, and keeps multiple counters accurate", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const html = await renderComponent(source, { + name: "team", + multiple: true, + values: ["design", "engineering"], + showCounter: true, + maxSelections: 3, + placeholder: "Choose teams", + options: [ + { value: "design", label: "Design" }, + { value: "engineering", label: "Engineering" }, + { value: "growth", label: "Growth" }, + ], + }); + const dom = mountHtml(html); + const trigger = dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement; + const counter = dom.querySelector(".wire-next__row small"); + expect(counter?.textContent).toBe("2 / 3 selected"); + + trigger.click(); + const buttons = dom.querySelectorAll(".wire-next__select-option") as HTMLButtonElement[]; + const scope = dom.querySelector("[data-wrn-select]") as HTMLElement & { + __wrnexusScopeApi?: { + get(name: string): unknown; + call(name: string, value?: unknown): unknown; + }; + }; + expect(scope.__wrnexusScopeApi?.get("maxSelections")).toBe(3); + expect(scope.__wrnexusScopeApi?.call("selectedCount")).toBe(2); + expect(scope.__wrnexusScopeApi?.call("canSelect", { value: "growth", label: "Growth" })).toBe( + true, + ); + expect(buttons.find((button) => button.textContent?.includes("Growth"))?.disabled).toBe(false); + buttons.find((button) => button.textContent?.includes("Engineering"))?.click(); + expect(counter?.textContent).toBe("1 / 3 selected"); + buttons.find((button) => button.textContent?.includes("Design"))?.click(); + expect(counter?.textContent).toBe("0 / 3 selected"); + expect( + dom.querySelector(".wire-next__placeholder")?.parentElement?.getAttribute("data-show"), + ).toBe("true"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe(""); +}); + +test("advanced select closes when a pointer event occurs outside it", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const html = await renderComponent(source, { + name: "team", + options: [{ value: "design", label: "Design" }], + }); + const dom = mountHtml(html); + (dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement).click(); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("true"); + dom.document.body.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("pointerdown", { bubbles: true }), + ); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("false"); +}); + +test("advanced select fetches remote options and appends infinite pages", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const originalFetch = globalThis.fetch; + const requests: string[] = []; + globalThis.fetch = (async (input: string | URL | Request) => { + const url = String(input); + requests.push(url); + const parsedUrl = new URL(url); + const page = parsedUrl.searchParams.get("page"); + const query = parsedUrl.searchParams.get("q"); + return Response.json( + page === "1" + ? { + items: query + ? [{ value: "engineering", label: "Engineering" }] + : [{ value: "design", label: "Design" }], + hasMore: true, + } + : { items: [{ value: "support", label: "Support" }], hasMore: false }, + ); + }) as unknown as typeof fetch; + + try { + const html = await renderComponent(source, { + name: "team", + options: [], + remote: true, + remoteUrl: "https://example.test/api/teams", + infinite: true, + hasMore: true, + remoteDebounce: 0, + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-select]") as HTMLElement & { + __wrnexusSelectController?: { attempts: number }; + __wrnexusScopeApi?: { get(name: string): unknown }; + }; + expect(root.getAttribute("data-remote")).toBe("true"); + expect(root.getAttribute("data-remote-url")).toBe("https://example.test/api/teams"); + expect(root.getAttribute("data-remote-auto-load")).toBe("true"); + expect(root.__wrnexusSelectController).toBeDefined(); + expect(root.__wrnexusScopeApi).toBeDefined(); + expect(root.__wrnexusScopeApi?.get("minSearchLength")).toBe(0); + expect(root.__wrnexusSelectController?.attempts).toBe(1); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(requests).toHaveLength(1); + expect( + dom.querySelectorAll(".wire-next__select-option").map((node) => node.textContent), + ).toEqual(["Design"]); + (dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement).click(); + (dom.querySelector(".wire-next__select-option") as HTMLButtonElement).click(); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe("design"); + expect(dom.querySelector(".wire-next__select-value > span")?.textContent).toBe("Design"); + + const search = dom.querySelector(".wire-next__select-search input") as HTMLInputElement; + search.value = "engine"; + search.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(requests.at(-1)).toContain("q=engine"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe("design"); + expect(dom.querySelector(".wire-next__select-value > span")?.textContent).toBe("Design"); + + (dom.querySelector("[data-wrn-select-load-more]") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect( + dom.querySelectorAll(".wire-next__select-option").map((node) => node.textContent), + ).toEqual(["Engineering", "Support"]); + expect(requests).toHaveLength(3); + expect(requests[2]).toContain("page=2"); + } finally { + globalThis.fetch = originalFetch; + } +}); + +test("combobox filters editable input, selects suggestions, exposes methods, and clears", async () => { + const source = readFileSync(uiComponentPath("ComboBox"), "utf8"); + const html = await renderComponent(source, { + name: "team", + placeholder: "Search teams", + options: [ + { value: "design", label: "Design", description: "Product design" }, + { value: "engineering", label: "Engineering", description: "Platform engineering" }, + { value: "growth", label: "Growth", description: "Customer growth" }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-combobox]") as HTMLElement & { + wrnexusCombobox?: { + open(): void; + close(): void; + clear(): void; + setValue(value: string): void; + }; + }; + const input = dom.querySelector(".wire-next__combobox-input") as HTMLInputElement; + const hidden = dom.querySelector('input[type="hidden"]') as HTMLInputElement; + + expect(root.wrnexusCombobox).toBeDefined(); + input.focus(); + input.value = "engi"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect( + dom + .querySelectorAll(".wire-next__select-option") + .filter((option) => (option as HTMLElement).style.display !== "none") + .map((option) => option.textContent?.trim()), + ).toEqual(["EngineeringPlatform engineering"]); + + input.value = "No matching team"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("false"); + expect(input.value).toBe("No matching team"); + + input.value = "engi"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + input.dispatchEvent( + new (dom.window as { KeyboardEvent: typeof KeyboardEvent }).KeyboardEvent("keydown", { + key: "Enter", + bubbles: true, + }), + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(input.value).toBe("Engineering"); + expect(hidden.value).toBe("engineering"); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("false"); + + root.wrnexusCombobox?.clear(); + expect(input.value).toBe(""); + expect(hidden.value).toBe(""); + root.wrnexusCombobox?.setValue("growth"); + expect(input.value).toBe("Growth"); + expect(hidden.value).toBe("growth"); +}); + +test("combobox auto-loads remote suggestions and retains its selected value while searching", async () => { + const source = readFileSync(uiComponentPath("ComboBox"), "utf8"); + const originalFetch = globalThis.fetch; + const requests: string[] = []; + globalThis.fetch = (async (input: string | URL | Request) => { + const url = new URL(String(input)); + requests.push(url.toString()); + const query = url.searchParams.get("q"); + return Response.json({ + items: query + ? [{ value: "engineering", label: "Engineering" }] + : [{ value: "design", label: "Design" }], + hasMore: false, + }); + }) as typeof fetch; + + try { + const html = await renderComponent(source, { + name: "remote-team", + remote: true, + remoteUrl: "https://example.test/api/teams", + remoteDebounce: 0, + }); + const dom = mountHtml(html); + const input = dom.querySelector(".wire-next__combobox-input") as HTMLInputElement; + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(requests).toHaveLength(1); + + input.focus(); + (dom.querySelector(".wire-next__select-option") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(input.value).toBe("Design"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe("design"); + + input.value = "engine"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(requests.at(-1)).toContain("q=engine"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe(""); + (dom.querySelector(".wire-next__select-option") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(input.value).toBe("Engineering"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe( + "engineering", + ); + } finally { + globalThis.fetch = originalFetch; + } +}); + +test("combobox emits search, select, change, clear, open, and close events", async () => { + const source = readFileSync(uiComponentPath("ComboBox"), "utf8"); + const html = await renderComponent(source, { + name: "events-team", + options: [ + { value: "design", label: "Design" }, + { value: "engineering", label: "Engineering" }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-combobox]") as HTMLElement; + const input = dom.querySelector(".wire-next__combobox-input") as HTMLInputElement; + const received: Array<{ name: string; detail: Record }> = []; + for (const name of ["search", "select", "change", "clear", "open", "close"]) { + root.addEventListener(`wrnexus:${name}`, ((event: CustomEvent) => { + received.push({ name, detail: event.detail }); + }) as EventListener); + } + + input.focus(); + await new Promise((resolve) => setTimeout(resolve, 0)); + input.value = "engi"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + input.dispatchEvent( + new (dom.window as { KeyboardEvent: typeof KeyboardEvent }).KeyboardEvent("keydown", { + key: "Enter", + bubbles: true, + }), + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + (dom.querySelector(".wire-next__clear-select") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + + expect(received.map((event) => event.name)).toEqual( + expect.arrayContaining(["search", "select", "change", "clear", "open", "close"]), + ); + expect(received.find((event) => event.name === "search")?.detail).toEqual( + expect.objectContaining({ component: "ComboBox", query: "engi" }), + ); + expect(received.find((event) => event.name === "select")?.detail).toEqual( + expect.objectContaining({ value: "engineering" }), + ); +}); + +test("advanced select emits selection events and remote load and error events", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const originalFetch = globalThis.fetch; + const originalConsoleError = console.error; + let rejectRequest = false; + globalThis.fetch = (async () => { + if (rejectRequest) throw new Error("Remote unavailable"); + return Response.json({ + items: [{ value: "design", label: "Design" }], + hasMore: false, + }); + }) as unknown as typeof fetch; + console.error = () => {}; + + try { + const html = await renderComponent(source, { + name: "advanced-events", + options: [], + remote: true, + remoteUrl: "https://example.test/api/teams", + remoteAutoLoad: true, + remoteDebounce: 0, + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-select]") as HTMLElement & { + __wrnexusSelectController?: { load(append: boolean, allowEmptyQuery?: boolean): void }; + }; + const received: Array<{ name: string; detail: Record }> = []; + for (const name of ["load", "error", "select", "change", "clear"]) { + root.addEventListener(`wrnexus:${name}`, ((event: CustomEvent) => { + received.push({ name, detail: event.detail }); + }) as EventListener); + } + + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + (dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement).click(); + (dom.querySelector(".wire-next__select-option") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + (dom.querySelector(".wire-next__clear-select") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + + rejectRequest = true; + root.__wrnexusSelectController?.load(false, true); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + + expect(received.map((event) => event.name)).toEqual( + expect.arrayContaining(["load", "select", "change", "clear", "error"]), + ); + expect(received.find((event) => event.name === "load")?.detail).toEqual( + expect.objectContaining({ + component: "AdvancedSelect", + page: 1, + hasMore: false, + }), + ); + expect(received.find((event) => event.name === "error")?.detail).toEqual( + expect.objectContaining({ + component: "AdvancedSelect", + message: "Remote unavailable", + }), + ); + } finally { + globalThis.fetch = originalFetch; + console.error = originalConsoleError; + } +}); + +test("pin input accepts matching characters, advances focus, navigates backward, and completes", async () => { + const source = readFileSync(uiComponentPath("PinInput"), "utf8"); + const html = await renderComponent(source, { + name: "verificationCode", + length: 4, + pattern: "[0-9]", + value: "", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-pin-input]") as HTMLElement & { + wrnexusPinInput?: { + focus(index?: number): void; + clear(): void; + setValue(value: string): void; + getValue(): string; + }; + }; + const cells = dom.querySelectorAll("[data-pin-cell]") as HTMLInputElement[]; + const hidden = dom.querySelector("[data-pin-value]") as HTMLInputElement; + const events: string[] = []; + const publicEvents: string[] = []; + for (const name of ["input", "change", "complete", "clear"]) { + root.addEventListener(`wrnexus:${name}`, () => events.push(name)); + root.addEventListener(name, () => publicEvents.push(name)); + } + + expect(cells).toHaveLength(4); + expect(root.wrnexusPinInput).toBeDefined(); + cells[0].focus(); + cells[0].value = "x"; + cells[0].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect(cells[0].value).toBe(""); + expect(hidden.value).toBe(""); + + for (let index = 0; index < 4; index += 1) { + cells[index].value = String(index + 1); + cells[index].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + } + expect(hidden.value).toBe("1234"); + expect(root.getAttribute("data-complete")).toBe("true"); + expect(events).toContain("complete"); + expect(publicEvents).toContain("complete"); + + cells[3].value = ""; + cells[3].dispatchEvent( + new (dom.window as { KeyboardEvent: typeof KeyboardEvent }).KeyboardEvent("keydown", { + key: "Backspace", + bubbles: true, + }), + ); + expect(cells[2].value).toBe(""); + expect(hidden.value).toBe("12"); + + root.wrnexusPinInput?.setValue("9876"); + expect(root.wrnexusPinInput?.getValue()).toBe("9876"); + root.wrnexusPinInput?.clear(); + expect(hidden.value).toBe(""); + expect(events).toContain("clear"); +}); + +test("pin input renders four separate cells when length is omitted", async () => { + const source = readFileSync(uiComponentPath("PinInput"), "utf8"); + const html = await renderComponent(source, { + name: "defaultPin", + }); + const dom = mountHtml(html); + + expect(dom.querySelectorAll("[data-pin-cell]")).toHaveLength(4); +}); + +test("pin input distributes filtered clipboard content and emits paste details", async () => { + const source = readFileSync(uiComponentPath("PinInput"), "utf8"); + const html = await renderComponent(source, { + name: "emailCode", + length: 6, + pattern: "[A-Z0-9]", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-pin-input]") as HTMLElement; + const firstCell = dom.querySelector("[data-pin-cell]") as HTMLInputElement; + let pasteDetail: Record | undefined; + root.addEventListener("wrnexus:paste", ((event: CustomEvent) => { + pasteDetail = event.detail; + }) as EventListener); + + const pasteEvent = new (dom.window as { Event: typeof Event }).Event("paste", { + bubbles: true, + cancelable: true, + }); + Object.defineProperty(pasteEvent, "clipboardData", { + value: { getData: () => "A-1b2 C3" }, + }); + firstCell.dispatchEvent(pasteEvent); + + expect((dom.querySelector("[data-pin-value]") as HTMLInputElement).value).toBe("A1B2C3"); + expect(pasteDetail).toEqual( + expect.objectContaining({ + component: "PinInput", + pasted: "A1B2C3", + value: "A1B2C3", + }), + ); +}); + +test("pin input accepts lowercase alphanumeric entry and normalizes it to the configured pattern", async () => { + const source = readFileSync(uiComponentPath("PinInput"), "utf8"); + const html = await renderComponent(source, { + name: "securityCode", + length: 4, + pattern: "[A-Z0-9]", + inputMode: "text", + }); + const dom = mountHtml(html); + const cells = dom.querySelectorAll("[data-pin-cell]") as HTMLInputElement[]; + + cells[0].value = "a"; + cells[0].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + + expect(cells[0].value).toBe("A"); + expect((dom.querySelector("[data-pin-value]") as HTMLInputElement).value).toBe("A"); +}); + +test("strong password scores input, supports custom special characters, and opens its popover", async () => { + const source = readFileSync(uiComponentPath("StrongPassword"), "utf8"); + const html = await renderComponent(source, { + name: "newPassword", + presentation: "popover", + specialCharactersSet: "@#", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-strong-password]") as HTMLElement; + const input = dom.querySelector('input[name="newPassword"]') as HTMLInputElement; + const strengthEvents: Array<{ level: string; percent: number }> = []; + root.addEventListener("strength", (event) => { + strengthEvents.push( + (event as unknown as CustomEvent<{ level: string; percent: number }>).detail, + ); + }); + + expect(input.minLength).toBe(8); + expect(root.dataset.strength).toBe("empty"); + + input.value = "Secure#9"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect((dom.querySelector("[data-wrn-strong-password]") as HTMLElement).dataset.strength).toBe( + "strong", + ); + expect((dom.querySelector("[data-wrn-strong-password]") as HTMLElement).dataset.score).toBe("5"); + expect(strengthEvents.at(-1)).toMatchObject({ level: "strong", percent: 100 }); + + const updatedInput = dom.querySelector('input[name="newPassword"]') as HTMLInputElement; + updatedInput.value = "Secure!9"; + updatedInput.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect((dom.querySelector("[data-wrn-strong-password]") as HTMLElement).dataset.strength).toBe( + "good", + ); + expect(strengthEvents.at(-1)?.percent).toBe(80); + + const currentInput = dom.querySelector('input[name="newPassword"]') as HTMLInputElement; + currentInput.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("focus", { bubbles: true }), + ); + expect( + (dom.querySelector(".wire-next__strong-password-popover") as HTMLElement).dataset.open, + ).toBe("true"); +}); + +test("strong password completed requirements use a proper checkmark indicator", () => { + const css = uiCss(); + + expect(css).toContain( + '.wire-next__strong-password-requirements li[data-met="true"] > span::after', + ); + expect(css).toContain("transform: rotate(45deg)"); + expect(css).toContain("border-width: 0 0.1rem 0.1rem 0"); + expect(css).not.toContain( + "linear-gradient(135deg, transparent 42%, var(--wire-color-surface) 42% 52%", + ); +}); + +test("toggle count switches pricing values and emits accessible change details", async () => { + const source = readFileSync(uiComponentPath("ToggleCount"), "utf8"); + const html = await renderComponent(source, { + name: "billing", + value: "monthly", + firstValue: "monthly", + firstLabel: "Monthly", + secondValue: "annual", + secondLabel: "Annual", + animate: false, + items: [ + { label: "Startup", monthly: 19, annual: 190 }, + { label: "Team", monthly: 89, annual: 890 }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-toggle-count]") as HTMLElement; + let detail: Record | undefined; + root.addEventListener("toggle", (event) => { + detail = (event as unknown as CustomEvent>).detail; + }); + + expect(root.dataset.value).toBe("monthly"); + expect( + dom + .querySelectorAll(".wire-next__toggle-count-items strong > span") + .map((node) => node.textContent), + ).toEqual(["19", "89"]); + + (dom.querySelector('button[aria-pressed="false"]') as HTMLButtonElement).click(); + + const updatedRoot = dom.querySelector("[data-wrn-toggle-count]") as HTMLElement; + expect(updatedRoot.dataset.value).toBe("annual"); + expect( + dom + .querySelectorAll(".wire-next__toggle-count-items strong > span") + .map((node) => node.textContent), + ).toEqual(["190", "890"]); + expect((dom.querySelector('input[name="billing"]') as HTMLInputElement).value).toBe("annual"); + expect(dom.querySelector('button[aria-pressed="true"]')?.textContent).toBe("Annual"); + expect(detail).toMatchObject({ + component: "ToggleCount", + name: "billing", + value: "annual", + previousValue: "monthly", + }); +}); + +test("toggle count animates every price upward and downward", async () => { + const source = readFileSync(uiComponentPath("ToggleCount"), "utf8"); + const html = await renderComponent(source, { + value: "monthly", + animationDuration: 40, + animationSteps: 4, + items: [ + { label: "Startup", monthly: 2, annual: 10 }, + { label: "Team", monthly: 4, annual: 20 }, + ], + }); + const dom = mountHtml(html); + const values = () => + dom.querySelectorAll("[data-toggle-count-value]").map((node) => Number(node.textContent)); + const button = (label: string) => + dom + .querySelectorAll(".wire-next__toggle-count-segmented button") + .find((node) => node.textContent === label) as HTMLButtonElement; + + button("Annual").click(); + expect(values()).toEqual([2, 4]); + await new Promise((resolve) => setTimeout(resolve, 15)); + expect(values().every((value) => Number.isInteger(value))).toBe(true); + await new Promise((resolve) => setTimeout(resolve, 80)); + expect(values()).toEqual([10, 20]); + + button("Monthly").click(); + expect(values()).toEqual([10, 20]); + await new Promise((resolve) => setTimeout(resolve, 15)); + expect(values().every((value) => Number.isInteger(value))).toBe(true); + await new Promise((resolve) => setTimeout(resolve, 80)); + expect(values()).toEqual([2, 4]); +}); + +test("toggle count switch exposes switch semantics and respects disabled state", async () => { + const source = readFileSync(uiComponentPath("ToggleCount"), "utf8"); + const html = await renderComponent(source, { + variant: "switch", + value: "monthly", + disabled: true, + items: [{ label: "Startup", monthly: 19, annual: 190 }], + }); + const dom = mountHtml(html); + const control = dom.querySelector('[role="switch"]') as HTMLButtonElement; + + expect(control.getAttribute("aria-checked")).toBe("false"); + expect(control.disabled).toBe(true); + control.click(); + expect((dom.querySelector("[data-wrn-toggle-count]") as HTMLElement).dataset.value).toBe( + "monthly", + ); +}); + +test("toggle password reveals and conceals its value with accessible declared events", async () => { + const source = readFileSync(uiComponentPath("TogglePassword"), "utf8"); + const html = await renderComponent(source, { + name: "accountPassword", + value: "correct-horse", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-toggle-password]") as HTMLElement; + const input = dom.querySelector('input[name="accountPassword"]') as HTMLInputElement; + const toggle = dom.querySelector(".wire-next__password-toggle") as HTMLButtonElement; + const showIcon = dom.querySelector(".wire-next__password-icon--show") as HTMLElement; + const visibility: boolean[] = []; + root.addEventListener("toggle", (event) => { + visibility.push((event as unknown as CustomEvent).detail.visible); + }); + + expect(input.type).toBe("password"); + expect(input.pattern).toBe("(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}"); + expect(showIcon).not.toBeNull(); + expect(toggle.getAttribute("aria-pressed")).toBe("false"); + toggle.click(); + expect(input.type).toBe("text"); + expect(input.value).toBe("correct-horse"); + expect(toggle.getAttribute("aria-pressed")).toBe("true"); + expect(visibility).toEqual([true]); + toggle.click(); + expect(input.type).toBe("password"); + expect(visibility).toEqual([true, false]); +}); + +test("toggle password supports checkbox control and synchronized password fields", async () => { + const source = readFileSync(uiComponentPath("TogglePassword"), "utf8"); + const synchronizedHtml = await renderComponent(source, { + name: "credentials", + fields: [ + { + label: "New password", + name: "newPassword", + placeholder: "Enter new password", + autocomplete: "new-password", + }, + { + label: "Current password", + name: "currentPassword", + value: "existing-secret", + autocomplete: "current-password", + pattern: ".{12,}", + }, + ], + }); + const synchronizedDom = mountHtml(synchronizedHtml); + const synchronizedInputs = synchronizedDom.querySelectorAll( + ".wire-next__password-control > input", + ) as HTMLInputElement[]; + const synchronizedToggle = synchronizedDom.querySelector( + ".wire-next__password-toggle", + ) as HTMLButtonElement; + + expect(synchronizedInputs).toHaveLength(2); + expect(synchronizedInputs[0].pattern).toBe( + "(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}", + ); + expect(synchronizedInputs[1].pattern).toBe(".{12,}"); + expect(synchronizedInputs.map((input) => input.type)).toEqual(["password", "password"]); + synchronizedToggle.click(); + expect(synchronizedInputs.map((input) => input.type)).toEqual(["text", "text"]); + + const checkboxHtml = await renderComponent(source, { + name: "checkboxPassword", + toggleMode: "checkbox", + }); + const checkboxDom = mountHtml(checkboxHtml); + const checkbox = checkboxDom.querySelector( + ".wire-next__password-checkbox input", + ) as HTMLInputElement; + const checkboxPassword = checkboxDom.querySelector( + ".wire-next__password-control > input", + ) as HTMLInputElement; + checkbox.checked = true; + checkbox.dispatchEvent( + new (checkboxDom.window as { Event: typeof Event }).Event("change", { bubbles: true }), + ); + + expect(checkboxPassword.type).toBe("text"); +}); diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Accordion.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Accordion.wrn new file mode 100644 index 00000000..8e75cc66 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Accordion.wrn @@ -0,0 +1,203 @@ +component Accordion { + props { + size = "default" + color = "primary" + variant = "default" + class = "" + + id = "accordion" + items = [] + defaultOpen = [] + multiple = false + alwaysOpen = false + disabled = false + + indicator = "plus" + indicatorPosition = "start" + showIndicator = true + bordered = false + separated = false + flush = false + contentItalic = false + + @event change = function + @event open = function + @event close = function + } + + state openValues = defaultOpen + + functions { + function itemValue(item, index) { + return item.value !== undefined && item.value !== "" + ? String(item.value) + : String(index) + } + + function nestedValue(parent, parentIndex, item, index) { + return itemValue(parent, parentIndex) + "." + itemValue(item, index) + } + + function isOpen(value) { + return openValues.includes(value) + } + + function allowsMultiple() { + return multiple || alwaysOpen + } + + function dispatchAccordionEvent(sourceEvent, eventName, value, item, root, customEvent) { + root = sourceEvent.currentTarget.closest("[data-wrn-accordion]") + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent(eventName, true, false, { + component: "Accordion", + value: value, + item: item, + open: isOpen(value), + openValues: openValues + }) + root.dispatchEvent(customEvent) + } + + function toggleItem(sourceEvent, value, item, wasOpen) { + if (disabled || item.disabled) { + return + } + + wasOpen = isOpen(value) + + if (wasOpen) { + openValues = openValues.filter((entry) => entry !== value) + } else if (allowsMultiple()) { + openValues = openValues.concat([value]) + } else { + openValues = [value] + } + + dispatchAccordionEvent( + sourceEvent, + wasOpen ? "close" : "open", + value, + item + ) + dispatchAccordionEvent(sourceEvent, "change", value, item) + } + + } + + view { +
+ {#each items as item, index} +
+

+ +

+ +
+
+
+ {#if item.content}

{item.content}

{/if} + + {#if item.children && item.children.length > 0} +
+ {#each item.children as child, childIndex} +
+

+ +

+
+
+
+

{child.content}

+
+
+
+
+ {/each} +
+ {/if} +
+
+
+
+ {/each} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AdvancedDatePicker.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AdvancedDatePicker.wrn new file mode 100644 index 00000000..e9664362 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AdvancedDatePicker.wrn @@ -0,0 +1,24 @@ +component AdvancedDatePicker { + props { + @event input = function + @event change = function + @event open = function + @event close = function + @event clear = function + size = "default" + color = "primary" + title = "Advanced Date Picker" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AdvancedRangeSlider.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AdvancedRangeSlider.wrn new file mode 100644 index 00000000..51090087 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AdvancedRangeSlider.wrn @@ -0,0 +1,23 @@ +component AdvancedRangeSlider { + props { + @event input = function + @event change = function + @event start = function + @event end = function + size = "default" + color = "primary" + title = "Advanced Range Slider" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AdvancedSelect.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AdvancedSelect.wrn new file mode 100644 index 00000000..6bd6fe16 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AdvancedSelect.wrn @@ -0,0 +1,456 @@ +component AdvancedSelect { + props { + size = "default" + color = "primary" + label = "Advanced Select" + name = "" + value = "" + values = [] + options = [] + groups = [] + placeholder = "Select an option" + placeholderIcon = "" + searchPlaceholder = "Search options…" + multiple = false + searchable = true + defaultOpen = false + clearable = true + allowEmpty = true + tags = false + disabled = false + required = false + invalid = false + validationMessage = "" + helpText = "" + loading = false + loadingLabel = "Loading options…" + emptyLabel = "No options found" + selectedOptionsLabel = "Selected options" + clearLabel = "Clear selection" + createLabel = "Create" + loadMoreLabel = "Load more" + searchMode = "contains" + searchFields = "label,description" + minSearchLength = 0 + searchResultLimit = 0 + maxSelections = 0 + showCounter = false + counterTemplate = "{selected} selected" + optionTemplate = "default" + selectedTemplate = "default" + closeOnSelect = true + scrollToSelected = true + fixed = false + placement = "bottom" + remote = false + remoteUrl = "" + remoteQueryParam = "q" + remoteDebounce = 250 + remoteAutoLoad = true + infinite = false + hasMore = false + page = 1 + class = "" + @event search = function + @event select = function + @event change = function + @event clear = function + @event open = function + @event close = function + @event load = function + @event error = function + } + + state open = defaultOpen + state query = "" + state activeIndex = -1 + state selectedValue = value + state selectedValues = values + + functions { + function allOptions() { + return [...groups.flatMap((group) => group.options || []), ...options] + } + + function searchableText(option) { + return ((option.label || "") + " " + (option.description || "")).toLowerCase() + } + + function matches(option) { + if (!query || query.length < Number(minSearchLength || 0)) { + return true + } + if (searchMode === "startsWith") { + return searchableText(option).startsWith(query.toLowerCase()) + } + if (searchMode === "exact") { + return searchableText(option) === query.toLowerCase() + } + return searchableText(option).includes(query.toLowerCase()) + } + + function matchingOptions(list) { + return list.filter((option) => matches(option)) + } + + function visibleOptions(list) { + if (searchResultLimit > 0) { + return matchingOptions(list).slice(0, Number(searchResultLimit)) + } + return matchingOptions(list) + } + + function flatVisibleOptions() { + return visibleOptions(allOptions()) + } + + function isSelected(option) { + return ( + multiple + ? selectedValues.includes(option.value) + : selectedValue === option.value + ) + } + + function selectedOptions() { + return allOptions().filter((option) => isSelected(option)) + } + + function selectedCount() { + return multiple ? selectedValues.length : selectedValue ? 1 : 0 + } + + function counterText() { + return ( + maxSelections + ? selectedCount() + " / " + maxSelections + " selected" + : selectedCount() + " selected" + ) + } + + function selectedText() { + return ( + multiple + ? selectedValues.join(", ") + : selectedOptions().length + ? selectedOptions()[0].label + : "" + ) + } + + function triggerText() { + return selectedCount() ? selectedText() : placeholder + } + + function canSelect(option) { + if (option.disabled) { + return false + } + if (!multiple || isSelected(option)) { + return true + } + if (maxSelections <= 0) { + return true + } + return selectedCount() < maxSelections + } + + function chooseSingle(option) { + if (!canSelect(option)) { + return + } + selectedValue = option.value + query = "" + if (closeOnSelect) { + open = false + } + } + + function chooseMultiple(option) { + if (!canSelect(option)) { + return + } + if (isSelected(option)) { + selectedValues = selectedValues.filter((item) => item !== option.value) + } else { + selectedValues = selectedValues.concat([option.value]) + } + query = "" + } + + function chooseOption(option) { + if (multiple) { + chooseMultiple(option) + return + } + chooseSingle(option) + } + + function clearSelection(event) { + event.stopPropagation() + selectedValue = "" + selectedValues = [] + query = "" + open = false + } + + function toggle() { + if (disabled) { + return; + }; + open = !open; + activeIndex = open && flatVisibleOptions().length ? 0 : -1; + } + + function moveActive(direction) { + if (!flatVisibleOptions().length) { + return + } + activeIndex = (activeIndex + direction + flatVisibleOptions().length) % flatVisibleOptions().length + } + + function handleKeydown(event) { + if (disabled) { + return + } + if (event.key === "ArrowDown") { + event.preventDefault() + if (!open) { + open = true + } + moveActive(1) + } else if (event.key === "ArrowUp") { + event.preventDefault() + if (!open) { + open = true + } + moveActive(-1) + } else if (event.key === "Enter" || event.key === " ") { + event.preventDefault() + if (!open) { + open = true + } else if (activeIndex >= 0) { + chooseOption(flatVisibleOptions()[activeIndex]) + } + } else if (event.key === "Escape") { + open = false + } else if (event.key === "Home" && open) { + event.preventDefault() + activeIndex = 0 + } else if (event.key === "End" && open) { + event.preventDefault() + activeIndex = flatVisibleOptions().length - 1 + } + } + + function optionIndex(option) { + return flatVisibleOptions().findIndex((item) => item.value === option.value) + } + } + + view { +
+
+ + {counterText()} +
+ +
+ + + +
+ +
+ {#if searchable} + + {/if} + +
Enter at least {minSearchLength} characters.
+
+ + {loadingLabel} +
+
+ {#each groups as group} + {#if visibleOptions(group.options || []).length} +
+
{group.label}
+ {#each group.options || [] as option} + + {/each} +
+ {/if} + {/each} + + {#each options as option} + + {/each} + + {#if !loading && !flatVisibleOptions().length} +
{emptyLabel}
+ {/if} +
+ + {#if tags && query && !allOptions().some((option) => option.label.toLowerCase() === query.toLowerCase())} + + {/if} + +
+ + + + {#if helpText && !validationMessage}{helpText}{/if} + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AnnouncementBar.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AnnouncementBar.wrn new file mode 100644 index 00000000..3e7341f8 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AnnouncementBar.wrn @@ -0,0 +1,131 @@ +component AnnouncementBar { + props { + badge = "" + badgeIcon = "" + message = "Announcement" + description = "" + icon = "icon-[lucide--megaphone]" + actionLabel = "" + actionHref = "" + actionIcon = "" + dismissible = false + dismissLabel = "Dismiss announcement" + sticky = false + compact = false + size = "default" + color = "primary" + variant = "soft" + role = "status" + live = "polite" + class = "" + } + + state dismissed = false + + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AuthForm.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AuthForm.wrn new file mode 100644 index 00000000..489e0fb4 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AuthForm.wrn @@ -0,0 +1,84 @@ +component AuthForm { + props { + @event submit = function + @event change = function + @event input = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + mode = "sign-in" + action = "/api/auth/login" + method = "post" + title = "Sign in" + description = "" + returnTo = "" + schema = "" + showRemember = true + showName = true + submitLabel = "Continue" + class = "" + } + + functions { + function schemaName() { + if (schema) return schema + if (mode === "sign-in") return "auth-login" + if (mode === "register") return "auth-register" + if (mode === "recover") return "auth-password-request" + if (mode === "reset") return "auth-password-reset" + if (mode === "mfa") return "auth-mfa" + return "auth-empty" + } + + function submitForm(event) { + $emit("submit", { event: event, mode: mode, action: action }) + } + function fieldEvent(type, event) { + const detail = event.detail || {} + $emit(type, { event: event, name: detail.name || "", value: detail.value || "" }) + } + } + + view { +
+
+ +

{title}

{#if description}

{description}

{/if}
+
+
+ {#if returnTo}{/if} + {#if mode === "register" && showName} + + {/if} + {#if mode === "sign-in" || mode === "register" || mode === "recover"} + + {/if} + {#if mode === "sign-in" || mode === "register" || mode === "reset"} + + {/if} + {#if mode === "register" || mode === "reset"} + + {/if} + {#if mode === "mfa"} + + {/if} + {#if mode === "sign-in" && showRemember} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AuthSplitLayout.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AuthSplitLayout.wrn new file mode 100644 index 00000000..771c2902 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AuthSplitLayout.wrn @@ -0,0 +1,83 @@ +component AuthSplitLayout { + props { + size = "default" + color = "primary" + eyebrow = "Secure identity" + title = "Welcome back" + description = "" + brand = "Police Management System" + features = [] + class = "" + } + + view { +
+
+
+ + {brand}Unified identity and access +
+
+ + {eyebrow} + +

{title}

+ {#if description} +

{description}

+ {/if} +
+ {#each features as item} +
+ + {item.label} + {#if item.description} + {item.description} + {/if} + +
+ {/each} +
+ +
+ + Authorised access only · Activity may be monitored and audited. + +
+
+
+ +
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AvatarGroup.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AvatarGroup.wrn new file mode 100644 index 00000000..45623306 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/AvatarGroup.wrn @@ -0,0 +1,151 @@ +component AvatarGroup { + props { + items = [] + size = "md" + color = "primary" + variant = "solid" + shape = "circle" + layout = "stack" + maxVisible = 4 + columns = 3 + borderColor = "" + showTooltips = true + overflowLabel = "Show remaining members" + class = "" + + @event overflow = function + } + + state overflowOpen = false + + functions { + function visibleMembers() { + return items.slice(0, Number(maxVisible)) + } + + function hiddenMembers() { + return items.slice(Number(maxVisible)) + } + + function toggleOverflow(sourceEvent, root, customEvent) { + overflowOpen = !overflowOpen + root = sourceEvent.currentTarget.closest("[data-wrn-avatar-group]") + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("overflow", true, false, { + component: "AvatarGroup", + open: overflowOpen, + hiddenCount: hiddenMembers().length + }) + root.dispatchEvent(customEvent) + } + } + + view { +
+
+ {#each visibleMembers() as item} + + + {#if item.src} + {item.alt || item.name || ''} + {:else if item.initials} + + {:else} + + {/if} + + + {#if showTooltips && (item.tooltip || item.name)} + + {item.tooltip || item.name} + + {/if} + + {/each} + + {#if hiddenMembers().length > 0} + + + + + {#each hiddenMembers() as item} + + + {#if item.src} + + {:else} + {item.initials || '?'} + {/if} + + {item.name || item.alt || item.initials || 'Team member'} + + {/each} + + + {/if} +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/BackToTop.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/BackToTop.wrn new file mode 100644 index 00000000..42d2e157 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/BackToTop.wrn @@ -0,0 +1,69 @@ +component BackToTop { + props { + threshold = 500 + label = "Back to top" + ariaLabel = "Scroll back to top" + icon = "icon-[lucide--arrow-up]" + position = "right" + offset = "md" + behavior = "smooth" + showProgress = false + size = "default" + color = "primary" + variant = "solid" + class = "" + } + + state visible = false + state progress = 0 + + view { + + } + + style { + .wire-back-to-top-progress { + background: conic-gradient( + currentColor var(--wire-back-to-top-progress), + transparent var(--wire-back-to-top-progress) + ); + opacity: 0.22; + } + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Badge.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Badge.wrn new file mode 100644 index 00000000..e5eb1c9b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Badge.wrn @@ -0,0 +1,102 @@ +component Badge { + props { + label = "Badge" + size = "md" + color = "primary" + variant = "solid" + shape = "pill" + class = "" + + icon = "" + iconPosition = "start" + dot = false + dotOnly = false + dotLabel = "Status" + animated = false + + avatarSrc = "" + avatarAlt = "" + dismissible = false + dismissLabel = "Remove badge" + truncate = false + maxWidth = "12rem" + + anchorLabel = "" + anchorIcon = "" + placement = "inline" + anchorLabelText = "Badge anchor" + + @event dismiss = function + } + + state visible = true + + functions { + function dismissBadge(sourceEvent, root, customEvent) { + visible = false + root = sourceEvent.currentTarget.closest("[data-wrn-badge]") + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("dismiss", true, false, { + component: "Badge", + label: label + }) + root.dispatchEvent(customEvent) + } + } + + view { + + {#if anchorLabel || anchorIcon} + + {/if} + + + {#if animated} + + {/if} + {#if avatarSrc} + {avatarAlt} + {/if} + {#if dot || dotOnly} + + {/if} + {#if icon && iconPosition === "start"} + + {/if} + {#if !dotOnly} + + {label} + + {/if} + {#if icon && iconPosition === "end"} + + {/if} + {#if dismissible} + + {/if} + + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Blockquote.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Blockquote.wrn new file mode 100644 index 00000000..dc476675 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Blockquote.wrn @@ -0,0 +1,67 @@ +component Blockquote { + props { + quote = "I just wanted to say that I'm very happy with my purchase so far. The documentation is outstanding - clear and detailed." + citation = "" + citationTitle = "" + citationUrl = "" + avatarSrc = "" + avatarAlt = "" + size = "md" + color = "primary" + align = "left" + variant = "default" + quoteMark = true + italic = true + class = "" + } + + view { +
+
+ {#if quoteMark} + + {/if} + +
+ {#if quote} +

{quote}

+ {:else} + + {/if} +
+
+ + {#if citation || citationTitle || avatarSrc} +
+ {#if avatarSrc} + {avatarAlt} + {/if} + + + {#if citation} + {#if citationUrl} + {citation} + {:else} + {citation} + {/if} + {/if} + {#if citationTitle}{citationTitle}{/if} + +
+ {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Breadcrumb.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Breadcrumb.wrn new file mode 100644 index 00000000..1fee40b5 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Breadcrumb.wrn @@ -0,0 +1,19 @@ +component Breadcrumb { + props { + @event navigate = function + @event click = function + size = "default" + color = "primary" + label = "Breadcrumb" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ButtonGroup.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ButtonGroup.wrn new file mode 100644 index 00000000..7430aba7 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ButtonGroup.wrn @@ -0,0 +1,89 @@ +component ButtonGroup { + props { + @event click = function + @event select = function + @event change = function + items = [] + value = "" + size = "md" + color = "primary" + variant = "default" + orientation = "horizontal" + responsive = false + attached = true + selectable = false + toolbar = false + disabled = false + ariaLabel = "Button group" + class = "" + } + + state selectedValue = value + + functions { + function itemValue(item, index) { + return item.value || item.label || String(index) + } + + function selectItem(item, index) { + previousValue = selectedValue + nextValue = itemValue(item, index) + + $emit("select", { + value: nextValue, + previousValue: previousValue, + item: item, + index: index + }) + + if (selectable && previousValue !== nextValue) { + selectedValue = nextValue + $emit("change", { + value: nextValue, + previousValue: previousValue, + item: item, + index: index + }) + } + } + } + + view { +
+ {#if items} + {#each items as item, index} + + {/each} + {/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/COMPONENTS.md b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/COMPONENTS.md new file mode 100644 index 00000000..bb322369 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/COMPONENTS.md @@ -0,0 +1,993 @@ +# WRNexus UI component reference + +This reference is generated from the 108 packaged `.wrn` component sources. Props marked required have no default; all others show their runtime default. + +## Advanced-forms + +### AdvancedSelect + +Theme-aware, responsive advanced select component. + +- Mount: `data-component="AdvancedSelect"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Advanced Select"`, `name: string = ""`, `value: string = ""`, `values: string = []`, `options: string = []`, `groups: string = []`, `placeholder: string = "Select an option"`, `placeholderIcon: string = ""`, `searchPlaceholder: string = "Search options…"`, `multiple: boolean = false`, `searchable: boolean = true`, `defaultOpen: boolean = false`, `clearable: boolean = true`, `allowEmpty: boolean = true`, `tags: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `invalid: boolean = false`, `validationMessage: string = ""`, `helpText: string = ""`, `loading: boolean = false`, `loadingLabel: string = "Loading options…"`, `emptyLabel: string = "No options found"`, `selectedOptionsLabel: string = "Selected options"`, `clearLabel: string = "Clear selection"`, `createLabel: string = "Create"`, `loadMoreLabel: string = "Load more"`, `searchMode: string = "contains"`, `searchFields: string = "label,description"`, `minSearchLength: number = 0`, `searchResultLimit: number = 0`, `maxSelections: number = 0`, `showCounter: boolean = false`, `counterTemplate: string = "{selected} selected"`, `optionTemplate: string = "default"`, `selectedTemplate: string = "default"`, `closeOnSelect: boolean = true`, `scrollToSelected: boolean = true`, `fixed: boolean = false`, `placement: string = "bottom"`, `remote: boolean = false`, `remoteUrl: string = ""`, `remoteQueryParam: string = "q"`, `remoteDebounce: number = 250`, `remoteAutoLoad: boolean = true`, `infinite: boolean = false`, `hasMore: boolean = false`, `page: number = 1`, `class: string = ""` +- Slots: None +- Events: `search`, `select`, `change`, `clear`, `open`, `close`, `load`, `error` + +### ComboBox + +Editable autocomplete combobox with local and remote suggestions. + +- Mount: `data-component="ComboBox"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "ComboBox"`, `name: string = ""`, `value: string = ""`, `options: string = []`, `groups: string = []`, `placeholder: string = "Search or select an option"`, `searchPlaceholder: string = "Start typing…"`, `clearable: boolean = true`, `allowCustomValue: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `invalid: boolean = false`, `validationMessage: string = ""`, `helpText: string = ""`, `loading: boolean = false`, `loadingLabel: string = "Loading suggestions…"`, `emptyLabel: string = "No matching options"`, `clearLabel: string = "Clear value"`, `toggleLabel: string = "Toggle suggestions"`, `searchMode: string = "contains"`, `searchFields: string = "label,description"`, `minSearchLength: number = 0`, `searchResultLimit: number = 0`, `optionTemplate: string = "default"`, `defaultOpen: boolean = false`, `closeOnSelect: boolean = true`, `fixed: boolean = false`, `placement: string = "bottom"`, `autocomplete: string = "off"`, `remote: boolean = false`, `remoteUrl: string = ""`, `remoteQueryParam: string = "q"`, `remoteDebounce: number = 250`, `remoteAutoLoad: boolean = true`, `infinite: boolean = false`, `hasMore: boolean = false`, `page: number = 1`, `loadMoreLabel: string = "Load more"`, `class: string = ""` +- Slots: None +- Events: `search`, `select`, `change`, `clear`, `open`, `close`, `load`, `error` + +### CopyMarkup + +Theme-aware, responsive copy markup component. + +- Mount: `data-component="CopyMarkup"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Copy Markup"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "text"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""` +- Slots: None +- Events: `copy`, `success`, `error` + +### InputNumber + +Theme-aware, responsive input number component. + +- Mount: `data-component="InputNumber"` +- Props: `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `class: string = ""`, `id: string = ""`, `name: string = "quantity"`, `value: number = 0`, `min: string = ""`, `max: string = ""`, `step: number = 1`, `precision: string = "auto"`, `label: string = ""`, `description: string = ""`, `helpText: string = ""`, `error: string = ""`, `invalid: boolean = false`, `prefix: string = ""`, `suffix: string = ""`, `placeholder: string = ""`, `autocomplete: string = "off"`, `inputMode: string = "decimal"`, `ariaLabel: string = ""`, `required: boolean = false`, `disabled: boolean = false`, `inputDisabled: boolean = false`, `buttonsDisabled: boolean = false`, `readonly: boolean = false`, `allowInput: boolean = true`, `keyboard: boolean = true`, `wheel: boolean = false`, `clamp: boolean = true`, `fullWidth: boolean = false`, `showButtons: boolean = true`, `showValidationMessage: boolean = true`, `decrementLabel: string = "Decrease value"`, `incrementLabel: string = "Increase value"`, `controlsLabel: string = "Quantity controls"`, `requiredMessage: string = "A value is required."`, `minMessage: string = "Value is below the minimum."`, `maxMessage: string = "Value is above the maximum."` +- Slots: None +- Events: `input`, `change`, `increment`, `decrement` + +### PinInput + +Secure multi-cell PIN and verification-code input with regex and paste support. + +- Mount: `data-component="PinInput"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Verification code"`, `name: string = "pin"`, `value: string = ""`, `length: number = 4`, `pattern: string = "[0-9]"`, `type: string = "text"`, `inputMode: string = "numeric"`, `placeholder: string = "○"`, `autocomplete: string = "one-time-code"`, `masked: boolean = false`, `disabled: boolean = false`, `readonly: boolean = false`, `required: boolean = false`, `autoFocus: boolean = false`, `autoSubmit: boolean = false`, `allowPaste: boolean = true`, `clearable: boolean = true`, `clearLabel: string = "Clear code"`, `separator: string = ""`, `groupSize: number = 0`, `helpText: string = ""`, `invalid: boolean = false`, `validationMessage: string = ""`, `class: string = ""` +- Slots: None +- Events: `input`, `change`, `complete`, `paste`, `clear`, `error` + +### SearchBox + +Theme-aware, responsive search box component. + +- Mount: `data-component="SearchBox"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Search Box"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "search"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""` +- Slots: None +- Events: None + +### StrongPassword + +Theme-aware, responsive strong password component. + +- Mount: `data-component="StrongPassword"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Password"`, `name: string = "password"`, `value: string = ""`, `placeholder: string = "Create a strong password"`, `autocomplete: string = "new-password"`, `minLength: number = 8`, `specialCharactersSet: string = "!@#$%^&*()_+-=[]{}|;:,.<>?"`, `requireLowercase: boolean = true`, `requireUppercase: boolean = true`, `requireNumber: boolean = true`, `requireSpecialCharacter: boolean = true`, `showRequirements: boolean = true`, `presentation: string = "inline"`, `hintText: string = "Use a unique password you do not use elsewhere."`, `emptyLabel: string = "Enter a password"`, `weakLabel: string = "Weak"`, `fairLabel: string = "Fair"`, `goodLabel: string = "Good"`, `strongLabel: string = "Strong"`, `disabled: boolean = false`, `readonly: boolean = false`, `required: boolean = false`, `invalid: boolean = false`, `validationMessage: string = ""`, `class: string = ""` +- Slots: None +- Events: `input`, `change`, `strength` + +### ToggleCount + +Theme-aware, responsive toggle count component. + +- Mount: `data-component="ToggleCount"` +- Props: `size: string = "default"`, `color: string = "primary"`, `variant: string = "segmented"`, `class: string = ""`, `name: string = "billing-cycle"`, `value: string = "monthly"`, `firstValue: string = "monthly"`, `firstLabel: string = "Monthly"`, `secondValue: string = "annual"`, `secondLabel: string = "Annual"`, `ariaLabel: string = "Billing frequency"`, `items: string = []`, `currency: string = "$"`, `suffix: string = ""`, `firstValueKey: string = "monthly"`, `secondValueKey: string = "annual"`, `emptyValue: string = "—"`, `align: string = "end"`, `fullWidth: boolean = true`, `disabled: boolean = false`, `animate: boolean = true`, `animationDuration: number = 450`, `animationSteps: number = 18` +- Slots: None +- Events: `change`, `toggle` + +### TogglePassword + +Accessible password field with optional show and hide controls. + +- Mount: `data-component="TogglePassword"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Password"`, `name: string = "password"`, `value: string = ""`, `placeholder: string = "Enter your password"`, `autocomplete: string = "current-password"`, `minlength: string = ""`, `maxlength: string = ""`, `pattern: string = "(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}"`, `fields: string = []`, `visible: boolean = false`, `toggleable: boolean = true`, `toggleMode: string = "button"`, `checkboxLabel: string = "Show password"`, `showLabel: string = "Show password"`, `hideLabel: string = "Hide password"`, `disabled: boolean = false`, `readonly: boolean = false`, `required: boolean = false`, `invalid: boolean = false`, `helpText: string = ""`, `validationMessage: string = ""`, `class: string = ""` +- Slots: None +- Events: `input`, `change`, `toggle` + +## Base + +### Accordion + +Theme-aware, responsive accordion component. + +- Mount: `data-component="Accordion"` +- Props: `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `class: string = ""`, `id: string = "accordion"`, `items: string = []`, `defaultOpen: string = []`, `multiple: boolean = false`, `alwaysOpen: boolean = false`, `disabled: boolean = false`, `indicator: string = "plus"`, `indicatorPosition: string = "start"`, `showIndicator: boolean = true`, `bordered: boolean = false`, `separated: boolean = false`, `flush: boolean = false`, `contentItalic: boolean = false` +- Slots: None +- Events: `change`, `open`, `close` + +### Alert + +Theme-aware, responsive alert component. + +- Mount: `data-component="Alert"` +- Props: `size: string = "default"`, `color: string = "info"`, `variant: string = "soft"`, `class: string = ""`, `radius: string = "md"`, `shadow: string = "sm"`, `title: string = "Alert"`, `description: string = ""`, `items: string = []`, `actions: string = []`, `showIcon: boolean = false`, `icon: string = ""`, `dismissible: boolean = false`, `dismissLabel: string = "Dismiss alert"`, `role: string = "alert"`, `live: string = "polite"`, `linkLabel: string = ""`, `linkHref: string = ""`, `actionLabel: string = ""`, `actionHref: string = ""`, `compact: boolean = false` +- Slots: None +- Events: `dismiss`, `action` + +### Avatar + +Theme-aware, responsive avatar component. + +- Mount: `data-component="Avatar"` +- Props: `src: string = ""`, `alt: string = ""`, `initials: string = ""`, `size: string = "md"`, `color: string = "primary"`, `variant: string = "solid"`, `shape: string = "circle"`, `status: string = ""`, `statusLabel: string = ""`, `statusPosition: string = "bottom"`, `badge: string = ""`, `badgeIcon: string = ""`, `badgeLabel: string = ""`, `tooltip: string = ""`, `name: string = ""`, `description: string = ""`, `loading: string = "lazy"`, `class: string = ""` +- Slots: None +- Events: `load`, `error`, `click` + +### AvatarGroup + +Theme-aware, responsive avatar group component. + +- Mount: `data-component="AvatarGroup"` +- Props: `items: string = []`, `size: string = "md"`, `color: string = "primary"`, `variant: string = "solid"`, `shape: string = "circle"`, `layout: string = "stack"`, `maxVisible: number = 4`, `columns: number = 3`, `borderColor: string = ""`, `showTooltips: boolean = true`, `overflowLabel: string = "Show remaining members"`, `class: string = ""` +- Slots: None +- Events: `overflow` + +### Badge + +Theme-aware, responsive badge component. + +- Mount: `data-component="Badge"` +- Props: `label: string = "Badge"`, `size: string = "md"`, `color: string = "primary"`, `variant: string = "solid"`, `shape: string = "pill"`, `class: string = ""`, `icon: string = ""`, `iconPosition: string = "start"`, `dot: boolean = false`, `dotOnly: boolean = false`, `dotLabel: string = "Status"`, `animated: boolean = false`, `avatarSrc: string = ""`, `avatarAlt: string = ""`, `dismissible: boolean = false`, `dismissLabel: string = "Remove badge"`, `truncate: boolean = false`, `maxWidth: string = "12rem"`, `anchorLabel: string = ""`, `anchorIcon: string = ""`, `placement: string = "inline"`, `anchorLabelText: string = "Badge anchor"` +- Slots: None +- Events: `dismiss` + +### Blockquote + +Theme-aware, responsive blockquote component. + +- Mount: `data-component="Blockquote"` +- Props: `quote: string = "I just wanted to say that I'm very happy with my purchase so far. The documentation is outstanding - clear and detailed."`, `citation: string = ""`, `citationTitle: string = ""`, `citationUrl: string = ""`, `avatarSrc: string = ""`, `avatarAlt: string = ""`, `size: string = "md"`, `color: string = "primary"`, `align: string = "left"`, `variant: string = "default"`, `quoteMark: boolean = true`, `italic: boolean = true`, `class: string = ""` +- Slots: `default` +- Events: None + +### Button + +Theme-aware, responsive button component. + +- Mount: `data-component="Button"` +- Props: `label: string = "Button"`, `loadingLabel: string = "Loading…"`, `description: string = ""`, `as: string = ""`, `href: string = ""`, `target: string = ""`, `rel: string = ""`, `type: string = "button"`, `variant: string = "default"`, `color: string = "primary"`, `size: string = "default"`, `disabled: boolean = false`, `loading: boolean = false`, `pill: boolean = false`, `fullWidth: boolean = false`, `icon: string = ""`, `iconPosition: string = "start"`, `ariaLabel: string = ""`, `ariaPressed: string = ""`, `ariaExpanded: string = ""`, `ariaControls: string = ""`, `title: string = ""`, `autofocus: boolean = false`, `controlClass: string = ""`, `class: string = ""` +- Slots: `default` +- Events: `click`, `focus`, `blur` + +### ButtonGroup + +Theme-aware, responsive button group component. + +- Mount: `data-component="ButtonGroup"` +- Props: `items: string = []`, `value: string = ""`, `size: string = "md"`, `color: string = "primary"`, `variant: string = "default"`, `orientation: string = "horizontal"`, `responsive: boolean = false`, `attached: boolean = true`, `selectable: boolean = false`, `toolbar: boolean = false`, `disabled: boolean = false`, `ariaLabel: string = "Button group"`, `class: string = ""` +- Slots: `default` +- Events: `click`, `select`, `change` + +### Card + +Theme-aware, responsive card component. + +- Mount: `data-component="Card"` +- Props: `title: string = "Card title"`, `subtitle: string = ""`, `description: string = ""`, `header: string = ""`, `footer: string = ""`, `imageSrc: string = ""`, `imageAlt: string = ""`, `imagePosition: string = "top"`, `actionLabel: string = ""`, `actionHref: string = ""`, `headerActions: string = []`, `navigation: string = []`, `activeNav: string = ""`, `mobileNavigation: boolean = false`, `alertTitle: string = ""`, `alertDescription: string = ""`, `empty: boolean = false`, `emptyTitle: string = "No data to show"`, `emptyIcon: string = "icon-[lucide--inbox]"`, `items: string = []`, `size: string = "md"`, `color: string = "primary"`, `variant: string = "default"`, `layout: string = "vertical"`, `align: string = "left"`, `hover: string = "none"`, `scrollable: boolean = false`, `maxHeight: string = "18rem"`, `dismissible: boolean = false`, `ariaLabel: string = ""`, `class: string = ""` +- Slots: `default` +- Events: `click`, `action`, `navigate`, `dismiss`, `load`, `error` + +### Carousel + +Theme-aware, responsive carousel component. + +- Mount: `data-component="Carousel"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = ""`, `description: string = ""`, `items: string = []`, `activeIndex: number = 0`, `slidesPerView: number = 1`, `gap: string = "0.75rem"`, `showPagination: boolean = false`, `isAutoPlay: boolean = false`, `autoplayInterval: number = 4000`, `isInfiniteLoop: boolean = false`, `isRTL: boolean = false`, `isCentered: boolean = false`, `isDraggable: boolean = false`, `isAutoHeight: boolean = false`, `isSnap: boolean = false`, `showCounter: boolean = false`, `thumbnails: string = "none"`, `ariaLabel: string = "Content carousel"`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `initialize`, `change`, `previous`, `next`, `play`, `pause`, `reachStart`, `reachEnd`, `dragStart`, `dragEnd` + +### ChatBubble + +Theme-aware, responsive chat bubble component. + +- Mount: `data-component="ChatBubble"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = ""`, `description: string = ""`, `items: string = []`, `oneSided: boolean = false`, `showAvatars: boolean = false`, `showMetadata: boolean = false`, `ariaLabel: string = "Conversation"`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `action`, `messageClick`, `avatarClick`, `linkClick` + +### Collapse + +Theme-aware, responsive collapse component. + +- Mount: `data-component="Collapse"` +- Props: `size: string = "default"`, `color: string = "primary"`, `items: string = []`, `multiple: boolean = false`, `mode: string = "panel"`, `initialOpenIndexes: string = []`, `ariaLabel: string = "Collapsible content"`, `class: string = ""` +- Slots: `default` +- Events: `toggle`, `open`, `close` + +### DatePicker + +Theme-aware, responsive date picker component. + +- Mount: `data-component="DatePicker"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Date Picker"`, `id: string = ""`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "date"`, `locale: string = "en-US"`, `firstDayOfWeek: number = 0`, `months: string = [{ label: "Jan", value: "01" }, { label: "Feb", value: "02" }, { label: "Mar", value: "03" }, { label: "Apr", value: "04" }, { label: "May", value: "05" }, { label: "Jun", value: "06" }, { label: "Jul", value: "07" }, { label: "Aug", value: "08" }, { label: "Sep", value: "09" }, { label: "Oct", value: "10" }, { label: "Nov", value: "11" }, { label: "Dec", value: "12" }]`, `days: string = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]`, `years: string = [2024, 2025, 2026, 2027, 2028, 2029, 2030]`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `variant: string = "normal"`, `inline: boolean = false`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""` +- Slots: None +- Events: `input`, `change`, `open`, `close`, `focus`, `blur`, `invalid` + +### DeviceFrame + +Theme-aware, responsive device frame component. + +- Mount: `data-component="DeviceFrame"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Device Frame"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `device: string = "phone"`, `orientation: string = "portrait"`, `src: string = ""`, `srcdoc: string = ""`, `frameTitle: string = "Device preview"`, `showToolbar: boolean = true`, `allow: string = ""`, `class: string = ""` +- Slots: `default` +- Events: `change`, `rotate` + +### FileUploadProgress + +Theme-aware, responsive file upload progress component. + +- Mount: `data-component="FileUploadProgress"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Progress"`, `value: number = 50`, `max: number = 100`, `showValue: boolean = true`, `fileName: string = ""`, `fileSize: string = ""`, `uploadedSize: string = ""`, `status: string = "uploading"`, `cancelLabel: string = "Cancel upload"`, `retryLabel: string = "Retry upload"`, `class: string = ""` +- Slots: None +- Events: `cancel`, `retry`, `complete` + +### HeroActions + +Responsive action group for hero and call-to-action sections. + +- Mount: `data-component="HeroActions"` +- Props: `actions: string = []`, `align: string = "left"`, `orientation: string = "horizontal"`, `stackOnMobile: boolean = true`, `fullWidthMobile: boolean = true`, `size: string = "default"`, `color: string = "primary"`, `class: string = ""` +- Slots: `default` +- Events: None + +### LegendIndicator + +Theme-aware, responsive legend indicator component. + +- Mount: `data-component="LegendIndicator"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Legend Indicator"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `toggle`, `select` + +### List + +Theme-aware, responsive list component. + +- Mount: `data-component="List"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "List"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: None + +### ListGroup + +Theme-aware, responsive list group component. + +- Mount: `data-component="ListGroup"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "List Group"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `select`, `change` + +### Marquee + +Theme-aware, responsive marquee component. + +- Mount: `data-component="Marquee"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Marquee"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: None + +### Progress + +Theme-aware, responsive progress component. + +- Mount: `data-component="Progress"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Progress"`, `value: number = 50`, `max: number = 100`, `showValue: boolean = true`, `class: string = ""` +- Slots: None +- Events: None + +### Rating + +Theme-aware, responsive rating component. + +- Mount: `data-component="Rating"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Rating"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `input`, `change` + +### Skeleton + +Theme-aware, responsive skeleton component. + +- Mount: `data-component="Skeleton"` +- Props: `color: string = "primary"`, `label: string = "Loading"`, `size: string = "md"`, `lines: number = 3`, `class: string = ""` +- Slots: None +- Events: None + +### Spinner + +Theme-aware, responsive spinner component. + +- Mount: `data-component="Spinner"` +- Props: `color: string = "primary"`, `label: string = "Loading"`, `size: string = "md"`, `lines: number = 3`, `class: string = ""` +- Slots: None +- Events: None + +### StyledIcon + +Theme-aware, responsive styled icon component. + +- Mount: `data-component="StyledIcon"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Styled Icon"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: None + +### Timeline + +Theme-aware, responsive timeline component. + +- Mount: `data-component="Timeline"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Timeline"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: None + +### Toast + +Theme-aware, responsive toast component. + +- Mount: `data-component="Toast"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Toast"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `dismiss`, `action` + +### TreeView + +Theme-aware, responsive tree view component. + +- Mount: `data-component="TreeView"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Tree View"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `select`, `toggle`, `expand`, `collapse` + +## Blocks + +### AnnouncementBar + +Accessible public announcement, emergency, maintenance, or status bar. + +- Mount: `data-component="AnnouncementBar"` +- Props: `badge: string = ""`, `badgeIcon: string = ""`, `message: string = "Announcement"`, `description: string = ""`, `icon: string = "icon-[lucide--megaphone]"`, `actionLabel: string = ""`, `actionHref: string = ""`, `actionIcon: string = ""`, `dismissible: boolean = false`, `dismissLabel: string = "Dismiss announcement"`, `sticky: boolean = false`, `compact: boolean = false`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "soft"`, `role: string = "status"`, `live: string = "polite"`, `class: string = ""` +- Slots: None +- Events: None + +### CTASection + +Reusable closing call-to-action section with primary and secondary actions. + +- Mount: `data-component="CTASection"` +- Props: `eyebrow: string = ""`, `title: string = "Ready to get started?"`, `description: string = ""`, `icon: string = ""`, `align: string = "center"`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "solid"`, `primaryLabel: string = "Get started"`, `primaryHref: string = "#"`, `primaryIcon: string = ""`, `secondaryLabel: string = ""`, `secondaryHref: string = ""`, `secondaryIcon: string = ""`, `backgroundImage: string = ""`, `maxWidth: string = "xl"`, `class: string = ""` +- Slots: `default`, `actions`, `visual`, `footer` +- Events: None + +### FeatureCard + +Reusable linked feature or service card with icon, badge, description, and action. + +- Mount: `data-component="FeatureCard"` +- Props: `icon: string = ""`, `title: string = "Feature"`, `description: string = ""`, `href: string = ""`, `actionLabel: string = "Learn more"`, `actionIcon: string = ""`, `badge: string = ""`, `badgeColor: string = "primary"`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `hover: string = "lift"`, `align: string = "left"`, `disabled: boolean = false`, `class: string = ""` +- Slots: `icon`, `default`, `footer` +- Events: None + +### FeatureIconCard + +Feature card with a prominent themed icon treatment. + +- Mount: `data-component="FeatureIconCard"` +- Props: `icon: string = "icon-[lucide--sparkles]"`, `iconSize: string = "md"`, `iconVariant: string = "soft"`, `title: string = "Feature"`, `description: string = ""`, `href: string = ""`, `actionLabel: string = "Explore"`, `badge: string = ""`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `align: string = "left"`, `hover: string = "lift"`, `class: string = ""` +- Slots: `default`, `footer` +- Events: None + +### Hero + +Reusable public-page hero with actions, trust items, badges, and visual slots. + +- Mount: `data-component="Hero"` +- Props: `eyebrow: string = ""`, `title: string = "Build something remarkable"`, `highlight: string = ""`, `description: string = ""`, `align: string = "left"`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `primaryLabel: string = ""`, `primaryHref: string = ""`, `primaryIcon: string = ""`, `secondaryLabel: string = ""`, `secondaryHref: string = ""`, `secondaryIcon: string = ""`, `tertiaryLabel: string = ""`, `tertiaryHref: string = ""`, `badges: string = []`, `trustItems: string = []`, `maxWidth: string = "xl"`, `class: string = ""` +- Slots: `eyebrow`, `actions`, `trust`, `default`, `visual`, `footer` +- Events: None + +### MarketingSectionHeader + +Marketing section heading with an optional linked action. + +- Mount: `data-component="MarketingSectionHeader"` +- Props: `id: string = ""`, `eyebrow: string = ""`, `title: string = ""`, `description: string = ""`, `align: string = "split"`, `size: string = "default"`, `color: string = "primary"`, `actionLabel: string = ""`, `actionHref: string = ""`, `actionIcon: string = ""`, `actionExternal: boolean = false`, `class: string = ""` +- Slots: `icon`, `actions`, `default` +- Events: None + +### MetricCard + +Single statistic or operational metric with icon, trend, and optional action. + +- Mount: `data-component="MetricCard"` +- Props: `label: string = "Metric"`, `value: string = "0"`, `description: string = ""`, `icon: string = ""`, `prefix: string = ""`, `suffix: string = ""`, `trend: string = ""`, `trendLabel: string = ""`, `trendDirection: string = "neutral"`, `href: string = ""`, `actionLabel: string = ""`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `align: string = "left"`, `class: string = ""` +- Slots: None +- Events: None + +### PageHeader + +Public and application page header with breadcrumbs, metadata, and actions. + +- Mount: `data-component="PageHeader"` +- Props: `eyebrow: string = ""`, `title: string = ""`, `description: string = ""`, `icon: string = ""`, `align: string = "left"`, `size: string = "default"`, `compact: boolean = false`, `showBreadcrumbs: boolean = false`, `breadcrumbs: string = []`, `primaryLabel: string = ""`, `primaryHref: string = ""`, `primaryIcon: string = ""`, `secondaryLabel: string = ""`, `secondaryHref: string = ""`, `secondaryIcon: string = ""`, `color: string = "primary"`, `variant: string = "default"`, `class: string = ""` +- Slots: `meta`, `actions`, `default` +- Events: None + +### PortalDashboard + +Responsive portal dashboard with metrics, actions, tasks, and updates. + +- Mount: `data-component="PortalDashboard"` +- Props: `size: string = "default"`, `color: string = "primary"`, `eyebrow: string = "Overview"`, `eyebrowKey: string = ""`, `title: string = "Dashboard"`, `titleKey: string = ""`, `description: string = ""`, `descriptionKey: string = ""`, `userName: string = ""`, `metrics: string = []`, `actions: string = []`, `updates: string = []`, `tasks: string = []`, `class: string = ""` +- Slots: `hero-action` +- Events: `action`, `navigate` + +### SplitHero + +Two-column hero with configurable content and visual placement. + +- Mount: `data-component="SplitHero"` +- Props: `eyebrow: string = ""`, `title: string = "A better digital experience"`, `highlight: string = ""`, `description: string = ""`, `primaryLabel: string = ""`, `primaryHref: string = ""`, `primaryIcon: string = ""`, `secondaryLabel: string = ""`, `secondaryHref: string = ""`, `secondaryIcon: string = ""`, `visualPosition: string = "right"`, `reverse: boolean = false`, `ratio: string = "balanced"`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `trustItems: string = []`, `class: string = ""` +- Slots: `actions`, `trust`, `default`, `visual` +- Events: None + +### StatsBar + +Compact responsive statistics strip. + +- Mount: `data-component="StatsBar"` +- Props: `items: string = []`, `columns: number = 4`, `compact: boolean = true`, `dividers: boolean = true`, `icons: boolean = true`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "raised"`, `maxWidth: string = "xl"`, `class: string = ""` +- Slots: None +- Events: None + +## Forms + +### AuthForm + +Reusable authentication form for sign-in, registration, recovery, reset, and MFA. + +- Mount: `data-component="AuthForm"` +- Props: `size: string = "default"`, `color: string = "primary"`, `mode: string = "sign-in"`, `action: string = "/api/auth/login"`, `method: string = "post"`, `title: string = "Sign in"`, `description: string = ""`, `returnTo: string = ""`, `schema: string = ""`, `showRemember: boolean = true`, `showName: boolean = true`, `submitLabel: string = "Continue"`, `class: string = ""` +- Slots: `default` +- Events: `submit`, `change`, `input`, `focus`, `blur` + +### Checkbox + +Theme-aware, responsive checkbox component. + +- Mount: `data-component="Checkbox"` +- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Checkbox"`, `hiddenLabel: boolean = false`, `placeholder: string = ""`, `variant: string = "normal"`, `icon: string = ""`, `iconPosition: string = "start"`, `value: string = "on"`, `values: string = []`, `options: string = []`, `checked: boolean = false`, `indeterminate: boolean = false`, `orientation: string = "vertical"`, `card: boolean = false`, `rightAligned: boolean = false`, `list: boolean = false`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""` +- Slots: `default` +- Events: `input`, `change`, `focus`, `blur`, `invalid` + +### ColorPicker + +Theme-aware, responsive color picker component. + +- Mount: `data-component="ColorPicker"` +- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Color"`, `hiddenLabel: boolean = false`, `placeholder: string = ""`, `value: string = "#2563eb"`, `icon: string = ""`, `iconPosition: string = "start"`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `variant: string = "normal"`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""` +- Slots: None +- Events: `input`, `change`, `focus`, `blur` + +### FileInput + +Theme-aware, responsive file input component. + +- Mount: `data-component="FileInput"` +- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "File"`, `hiddenLabel: boolean = false`, `placeholder: string = "Choose a file"`, `value: string = ""`, `icon: string = "icon-[lucide--upload]"`, `iconPosition: string = "start"`, `accept: string = ""`, `multiple: boolean = false`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `variant: string = "normal"`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""` +- Slots: None +- Events: `input`, `change`, `focus`, `blur`, `select`, `clear`, `invalid` + +### Input + +Theme-aware, responsive input component. + +- Mount: `data-component="Input"` +- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Input"`, `hiddenLabel: boolean = false`, `placeholder: string = ""`, `value: string = ""`, `type: string = "text"`, `variant: string = "normal"`, `icon: string = ""`, `iconPosition: string = "start"`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `autocomplete: string = ""`, `inputmode: string = ""`, `minlength: string = ""`, `maxlength: string = ""`, `pattern: string = ""`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `class: string = ""` +- Slots: None +- Events: `input`, `change`, `focus`, `blur`, `invalid`, `keydown`, `keyup` + +### InputGroup + +Theme-aware, responsive input group component. + +- Mount: `data-component="InputGroup"` +- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Input group"`, `hiddenLabel: boolean = false`, `value: string = ""`, `placeholder: string = ""`, `type: string = "text"`, `startText: string = ""`, `endText: string = ""`, `icon: string = ""`, `iconPosition: string = "start"`, `actionLabel: string = ""`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `variant: string = "normal"`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""` +- Slots: None +- Events: `input`, `change`, `focus`, `blur`, `submit`, `action` + +### Radio + +Theme-aware, responsive radio component. + +- Mount: `data-component="Radio"` +- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Radio"`, `hiddenLabel: boolean = false`, `placeholder: string = ""`, `variant: string = "normal"`, `icon: string = ""`, `iconPosition: string = "start"`, `value: string = "on"`, `options: string = []`, `checked: boolean = false`, `orientation: string = "vertical"`, `card: boolean = false`, `rightAligned: boolean = false`, `list: boolean = false`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""` +- Slots: None +- Events: `input`, `change`, `focus`, `blur`, `invalid` + +### RangeSlider + +Theme-aware, responsive range slider component. + +- Mount: `data-component="RangeSlider"` +- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Range"`, `hiddenLabel: boolean = false`, `placeholder: string = ""`, `variant: string = "normal"`, `icon: string = ""`, `iconPosition: string = "start"`, `value: number = 50`, `min: number = 0`, `max: number = 100`, `step: number = 1`, `showValue: boolean = true`, `showBounds: boolean = true`, `showSteps: boolean = false`, `marks: string = []`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""` +- Slots: None +- Events: `input`, `change`, `focus`, `blur` + +### Select + +Theme-aware, responsive select component. + +- Mount: `data-component="Select"` +- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Select"`, `hiddenLabel: boolean = false`, `value: string = ""`, `values: string = []`, `options: string = []`, `placeholder: string = "Select an option"`, `variant: string = "normal"`, `icon: string = ""`, `iconPosition: string = "start"`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `multiple: boolean = false`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""` +- Slots: None +- Events: `input`, `change`, `focus`, `blur`, `open`, `close`, `invalid` + +### Switch + +Theme-aware, responsive switch component. + +- Mount: `data-component="Switch"` +- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Switch"`, `hiddenLabel: boolean = false`, `placeholder: string = ""`, `variant: string = "normal"`, `icon: string = ""`, `iconPosition: string = "start"`, `value: string = "on"`, `checked: boolean = false`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""` +- Slots: None +- Events: `input`, `change`, `focus`, `blur` + +### Textarea + +Theme-aware, responsive textarea component. + +- Mount: `data-component="Textarea"` +- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Textarea"`, `hiddenLabel: boolean = false`, `placeholder: string = ""`, `value: string = ""`, `variant: string = "normal"`, `icon: string = ""`, `iconPosition: string = "start"`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `rows: number = 5`, `resize: string = "vertical"`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `minlength: string = ""`, `maxlength: string = ""`, `class: string = ""` +- Slots: None +- Events: `input`, `change`, `focus`, `blur`, `invalid` + +### TimePicker + +Theme-aware, responsive time picker component. + +- Mount: `data-component="TimePicker"` +- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Time"`, `hiddenLabel: boolean = false`, `value: string = ""`, `placeholder: string = ""`, `variant: string = "normal"`, `icon: string = "icon-[lucide--clock-3]"`, `iconPosition: string = "end"`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `format: string = "24"`, `minuteStep: number = 5`, `hours: string = ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"]`, `minutes: string = ["00", "05", "10", "15", "20", "25", "30", "35", "40", "45", "50", "55"]`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""` +- Slots: None +- Events: `input`, `change`, `focus`, `blur`, `open`, `close`, `invalid` + +## Integrations + +### AdvancedDatePicker + +Theme-aware, responsive advanced date picker component. + +- Mount: `data-component="AdvancedDatePicker"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Advanced Date Picker"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `input`, `change`, `open`, `close`, `clear` + +### AdvancedRangeSlider + +Theme-aware, responsive advanced range slider component. + +- Mount: `data-component="AdvancedRangeSlider"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Advanced Range Slider"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `input`, `change`, `start`, `end` + +### Chart + +Theme-aware, responsive chart component. + +- Mount: `data-component="Chart"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Chart"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `select`, `dataPointClick`, `legendToggle` + +### Clipboard + +Theme-aware, responsive clipboard component. + +- Mount: `data-component="Clipboard"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Clipboard"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `copy`, `success`, `error` + +### Confetti + +Theme-aware, responsive confetti component. + +- Mount: `data-component="Confetti"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Confetti"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `start`, `complete` + +### DataMap + +Theme-aware, responsive data map component. + +- Mount: `data-component="DataMap"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Data Map"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `select`, `change` + +### DataTable + +Theme-aware, responsive data table component. + +- Mount: `data-component="DataTable"` +- Props: `size: string = "default"`, `color: string = "primary"`, `caption: string = "Data Table"`, `columns: string = []`, `rows: string = []`, `striped: boolean = true`, `class: string = ""` +- Slots: `default` +- Events: `sort`, `select`, `change`, `rowClick`, `pageChange` + +### DragAndDrop + +Theme-aware, responsive drag and drop component. + +- Mount: `data-component="DragAndDrop"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Drag And Drop"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `dragStart`, `dragEnd`, `dragEnter`, `dragLeave`, `drop`, `change` + +### FileUpload + +Theme-aware, responsive file upload component. + +- Mount: `data-component="FileUpload"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "File Upload"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `select`, `upload`, `progress`, `success`, `error`, `cancel`, `remove` + +### Map + +Theme-aware, responsive map component. + +- Mount: `data-component="Map"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Map"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: None + +### ToastNotifications + +Theme-aware, responsive toast notifications component. + +- Mount: `data-component="ToastNotifications"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Toast Notifications"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `add`, `dismiss`, `clear`, `action` + +### WysiwygEditor + +Theme-aware, responsive wysiwyg editor component. + +- Mount: `data-component="WysiwygEditor"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Wysiwyg Editor"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: `input`, `change`, `focus`, `blur` + +## Layout + +### AuthSplitLayout + +Responsive 50/50 authentication layout with content and form regions. + +- Mount: `data-component="AuthSplitLayout"` +- Props: `size: string = "default"`, `color: string = "primary"`, `eyebrow: string = "Secure identity"`, `title: string = "Welcome back"`, `description: string = ""`, `brand: string = "Police Management System"`, `features: string = []`, `class: string = ""` +- Slots: `aside-extra`, `form` +- Events: None + +### Columns + +Theme-aware, responsive columns component. + +- Mount: `data-component="Columns"` +- Props: `size: string = "default"`, `color: string = "primary"`, `columns: number = 2`, `gap: string = "md"`, `maxWidth: string = "xl"`, `class: string = ""` +- Slots: `default` +- Events: None + +### Container + +Theme-aware, responsive container component. + +- Mount: `data-component="Container"` +- Props: `size: string = "default"`, `color: string = "primary"`, `columns: number = 2`, `gap: string = "md"`, `maxWidth: string = "xl"`, `class: string = ""` +- Slots: `default` +- Events: None + +### CustomScrollbar + +Theme-aware, responsive custom scrollbar component. + +- Mount: `data-component="CustomScrollbar"` +- Props: `size: string = "default"`, `color: string = "primary"`, `columns: number = 2`, `gap: string = "md"`, `maxWidth: string = "xl"`, `class: string = ""` +- Slots: `default` +- Events: `scroll` + +### Divider + +Theme-aware, responsive divider component. + +- Mount: `data-component="Divider"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = ""`, `orientation: string = "horizontal"`, `class: string = ""` +- Slots: None +- Events: None + +### FeatureGrid + +Responsive equal-height grid for feature and service cards. + +- Mount: `data-component="FeatureGrid"` +- Props: `color: string = "primary"`, `size: string = "default"`, `columns: number = 3`, `tabletColumns: number = 2`, `mobileColumns: number = 1`, `gap: string = "md"`, `minItemWidth: string = ""`, `equalHeight: boolean = true`, `align: string = "stretch"`, `maxWidth: string = "full"`, `class: string = ""` +- Slots: `default` +- Events: None + +### Grid + +Theme-aware, responsive grid component. + +- Mount: `data-component="Grid"` +- Props: `size: string = "default"`, `color: string = "primary"`, `columns: number = 2`, `gap: string = "md"`, `maxWidth: string = "xl"`, `class: string = ""` +- Slots: `default` +- Events: None + +### Image + +Theme-aware, responsive image component. + +- Mount: `data-component="Image"` +- Props: `size: string = "default"`, `color: string = "primary"`, `src: string = ""`, `alt: string = ""`, `width: string = ""`, `height: string = ""`, `loading: string = "lazy"`, `rounded: boolean = false`, `class: string = ""` +- Slots: `default` +- Events: None + +### Kbd + +Theme-aware, responsive kbd component. + +- Mount: `data-component="Kbd"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "⌘ K"`, `class: string = ""` +- Slots: `default` +- Events: None + +### LayoutSplitter + +Theme-aware, responsive layout splitter component. + +- Mount: `data-component="LayoutSplitter"` +- Props: `size: string = "default"`, `color: string = "primary"`, `columns: number = 2`, `gap: string = "md"`, `maxWidth: string = "xl"`, `class: string = ""` +- Slots: `default` +- Events: `resizeStart`, `resize`, `resizeEnd` + +### Link + +Theme-aware, responsive link component. + +- Mount: `data-component="Link"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Link"`, `href: string = "#"`, `target: string = ""`, `rel: string = ""`, `external: boolean = false`, `class: string = ""` +- Slots: `default` +- Events: None + +### MetricGrid + +Responsive collection of metric cards. + +- Mount: `data-component="MetricGrid"` +- Props: `items: string = []`, `columns: number = 4`, `tabletColumns: number = 2`, `mobileColumns: number = 1`, `gap: string = "md"`, `equalHeight: boolean = true`, `dividers: boolean = false`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `class: string = ""` +- Slots: `default` +- Events: None + +### PublicPageShell + +Consistent structural wrapper for public-facing pages. + +- Mount: `data-component="PublicPageShell"` +- Props: `maxWidth: string = "full"`, `fullWidth: boolean = true`, `headerOffset: string = "none"`, `background: string = "default"`, `overflow: string = "clip"`, `minHeight: string = "screen"`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `class: string = ""` +- Slots: `before`, `default`, `after` +- Events: None + +### Section + +Theme-aware page section with consistent spacing, width, background, and border controls. + +- Mount: `data-component="Section"` +- Props: `id: string = ""`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `spacing: string = "lg"`, `maxWidth: string = "xl"`, `fullWidth: boolean = false`, `borderTop: boolean = false`, `borderBottom: boolean = false`, `class: string = ""` +- Slots: `default` +- Events: None + +### SectionHeader + +Reusable accessible section heading with eyebrow, title, description, icon, and actions. + +- Mount: `data-component="SectionHeader"` +- Props: `id: string = ""`, `eyebrow: string = ""`, `title: string = ""`, `description: string = ""`, `align: string = "left"`, `size: string = "default"`, `color: string = "primary"`, `headingLevel: number = 2`, `maxWidth: string = "3xl"`, `class: string = ""` +- Slots: `icon`, `default`, `actions` +- Events: None + +### TextLink + +Styled inline action link with icons, arrows, external state, and disabled handling. + +- Mount: `data-component="TextLink"` +- Props: `label: string = "Learn more"`, `href: string = "#"`, `target: string = ""`, `rel: string = ""`, `external: boolean = false`, `icon: string = ""`, `iconPosition: string = "start"`, `showArrow: boolean = true`, `underline: boolean = false`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `disabled: boolean = false`, `class: string = ""` +- Slots: None +- Events: `click`, `focus`, `blur` + +### Typography + +Theme-aware, responsive typography component. + +- Mount: `data-component="Typography"` +- Props: `size: string = "default"`, `color: string = "primary"`, `columns: number = 2`, `gap: string = "md"`, `maxWidth: string = "xl"`, `class: string = ""` +- Slots: `default` +- Events: None + +## Navigation + +### BackToTop + +Accessible scroll-to-top control with visibility threshold. + +- Mount: `data-component="BackToTop"` +- Props: `threshold: number = 500`, `label: string = "Back to top"`, `ariaLabel: string = "Scroll back to top"`, `icon: string = "icon-[lucide--arrow-up]"`, `position: string = "right"`, `offset: string = "md"`, `behavior: string = "smooth"`, `showProgress: boolean = false`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "solid"`, `class: string = ""` +- Slots: None +- Events: None + +### Breadcrumb + +Theme-aware, responsive breadcrumb component. + +- Mount: `data-component="Breadcrumb"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Breadcrumb"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""` +- Slots: `default` +- Events: `navigate`, `click` + +### Footer + +Responsive application footer with structured links and pre/post content slots. + +- Mount: `data-component="Footer"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Footer navigation"`, `items: string = []`, `columns: number = 3`, `maxWidth: string = "compact"`, `copyright: string = ""`, `class: string = ""` +- Slots: `pre-footer`, `copyright-left`, `copyright-right`, `post-footer` +- Events: `select`, `action` + +### MegaMenu + +Theme-aware, responsive mega menu component. + +- Mount: `data-component="MegaMenu"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Mega Menu"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""` +- Slots: `default` +- Events: `open`, `close`, `select` + +### Nav + +Theme-aware, responsive nav component. + +- Mount: `data-component="Nav"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Nav"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""` +- Slots: `default` +- Events: `select`, `change` + +### Navbar + +Theme-aware, responsive navbar component. + +- Mount: `data-component="Navbar"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Primary navigation"`, `topbarLabel: string = "Utility navigation"`, `brand: string = {}`, `items: string = []`, `actions: string = []`, `active: string = ""`, `sticky: boolean = false`, `openOnHover: boolean = false`, `maxWidth: string = "full"`, `mobileLabel: string = "Toggle navigation"`, `class: string = ""` +- Slots: `topbar`, `actions` +- Events: `toggle`, `open`, `close`, `select`, `action` + +### Pagination + +Theme-aware, responsive pagination component. + +- Mount: `data-component="Pagination"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Pagination"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""` +- Slots: `default` +- Events: `change`, `previous`, `next` + +### PreferenceSwitcher + +Accessible theme, accent color, and language preference controls. + +- Mount: `data-component="PreferenceSwitcher"` +- Props: `size: string = "default"`, `color: string = "primary"`, `themeLabel: string = "Theme"`, `colorLabel: string = "Accent color"`, `languageLabel: string = "Language"`, `languages: string = [`, `colors: string = [`, `compact: boolean = true`, `class: string = ""` +- Slots: None +- Events: `theme`, `color`, `language` + +### Scrollspy + +Theme-aware, responsive scrollspy component. + +- Mount: `data-component="Scrollspy"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Scrollspy"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""` +- Slots: `default` +- Events: `change` + +### Sidebar + +Theme-aware, responsive sidebar component. + +- Mount: `data-component="Sidebar"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Sidebar"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `mobileLabel: string = "Open navigation"`, `class: string = ""` +- Slots: `default` +- Events: `toggle`, `open`, `close`, `select` + +### Stepper + +Theme-aware, responsive stepper component. + +- Mount: `data-component="Stepper"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Stepper"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""` +- Slots: `default` +- Events: `change`, `previous`, `next`, `complete` + +### Tabs + +Theme-aware, responsive tabs component. + +- Mount: `data-component="Tabs"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Tabs"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""` +- Slots: `default` +- Events: None + +## Overlays + +### ContextMenu + +Theme-aware, responsive context menu component. + +- Mount: `data-component="ContextMenu"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Context Menu"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""` +- Slots: `default` +- Events: `open`, `close`, `select` + +### Drawer + +Theme-aware, responsive drawer component. + +- Mount: `data-component="Drawer"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Drawer"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""` +- Slots: `default` +- Events: `open`, `close` + +### Dropdown + +Theme-aware, responsive dropdown component. + +- Mount: `data-component="Dropdown"` +- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Open menu"`, `items: string = []`, `placement: string = "end"`, `class: string = ""` +- Slots: `trigger`, `header`, `footer` +- Events: `toggle`, `open`, `close`, `select` + +### Modal + +Theme-aware, responsive modal component. + +- Mount: `data-component="Modal"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Modal"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""` +- Slots: `default` +- Events: `open`, `close`, `cancel`, `confirm` + +### Popover + +Theme-aware, responsive popover component. + +- Mount: `data-component="Popover"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Popover"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""` +- Slots: `default` +- Events: `open`, `close` + +### Tooltip + +Theme-aware, responsive tooltip component. + +- Mount: `data-component="Tooltip"` +- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Tooltip"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""` +- Slots: `default` +- Events: `open`, `close` + +## Tables + +### Table + +Theme-aware, responsive table component. + +- Mount: `data-component="Table"` +- Props: `size: string = "default"`, `color: string = "primary"`, `caption: string = "Table"`, `columns: string = []`, `rows: string = []`, `striped: boolean = true`, `class: string = ""` +- Slots: `default` +- Events: `sort`, `select`, `rowClick` diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/CTASection.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/CTASection.wrn new file mode 100644 index 00000000..36453a83 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/CTASection.wrn @@ -0,0 +1,150 @@ +component CTASection { + props { + eyebrow = "" + title = "Ready to get started?" + description = "" + icon = "" + align = "center" + size = "default" + color = "primary" + variant = "solid" + primaryLabel = "Get started" + primaryHref = "#" + primaryIcon = "" + secondaryLabel = "" + secondaryHref = "" + secondaryIcon = "" + backgroundImage = "" + maxWidth = "xl" + class = "" + } + + view { +
+
+ {#if backgroundImage} + + {/if} + + + + +
+
+ {#if icon} + + + + {/if} + + {#if eyebrow} +

+ {eyebrow} +

+ {/if} + +

+ {title} +

+ + {#if description} +

+ {description} +

+ {/if} + + +
+ + + + + + +
+ + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Card.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Card.wrn new file mode 100644 index 00000000..ecbcfc7c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Card.wrn @@ -0,0 +1,284 @@ +component Card { + props { + @event click = function + @event action = function + @event navigate = function + @event dismiss = function + @event load = function + @event error = function + title = "Card title" + subtitle = "" + description = "" + header = "" + footer = "" + imageSrc = "" + imageAlt = "" + imagePosition = "top" + actionLabel = "" + actionHref = "" + headerActions = [] + navigation = [] + activeNav = "" + mobileNavigation = false + alertTitle = "" + alertDescription = "" + empty = false + emptyTitle = "No data to show" + emptyIcon = "icon-[lucide--inbox]" + items = [] + size = "md" + color = "primary" + variant = "default" + layout = "vertical" + align = "left" + hover = "none" + scrollable = false + maxHeight = "18rem" + dismissible = false + ariaLabel = "" + class = "" + } + + state dismissed = false + + view { +
+ {#if items.length > 0} +
+ {#each items as item, itemIndex} +
+ {#if item.imageSrc || item.image} +
+ {item.imageAlt || item.alt || ""} +
+ {/if} + +
+ {#if item.title || item.label} +

{item.title || item.label}

+ {/if} + {#if item.subtitle} +

{item.subtitle}

+ {/if} + {#if item.description} +

{item.description}

+ {/if} + {#if item.actionLabel || item.href} + + {item.actionLabel || "Learn more"} + + + {/if} +
+
+ {/each} +
+ {:else} +
+ {#if imageSrc && imagePosition === "overlay"} +
+ {imageAlt} + +
+ {/if} + + {#if imageSrc && (imagePosition === "top" || imagePosition === "left")} +
+ {imageAlt} +
+ {/if} + +
+ {#if header || title || subtitle || headerActions.length > 0 || dismissible} +
+
+ {#if header} +

{header}

+ {/if} + {#if title} +

{title}

+ {/if} + {#if subtitle} +

{subtitle}

+ {/if} +
+ + {#if headerActions.length > 0 || dismissible} +
+ {#each headerActions as headerAction, actionIndex} + + {/each} + + {#if dismissible} + + {/if} +
+ {/if} +
+ {/if} + + {#if navigation.length > 0} + + {/if} + + {#if alertTitle || alertDescription} +
+ {#if alertTitle} + {alertTitle} + {/if} + {#if alertDescription} +

{alertDescription}

+ {/if} +
+ {/if} + +
+ {#if empty} +
+ +

{emptyTitle}

+
+ {:else} + {#if description} +

{description}

+ {/if} + + {/if} +
+ + {#if footer || actionLabel} + + {/if} +
+ + {#if imageSrc && (imagePosition === "bottom" || imagePosition === "right")} +
+ {imageAlt} +
+ {/if} +
+ {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Chart.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Chart.wrn new file mode 100644 index 00000000..d491c5ae --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Chart.wrn @@ -0,0 +1,22 @@ +component Chart { + props { + @event select = function + @event dataPointClick = function + @event legendToggle = function + size = "default" + color = "primary" + title = "Chart" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ChatBubble.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ChatBubble.wrn new file mode 100644 index 00000000..947f6995 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ChatBubble.wrn @@ -0,0 +1,147 @@ +component ChatBubble { + props { + @event action = function + @event messageClick = function + @event avatarClick = function + @event linkClick = function + size = "default" + color = "primary" + title = "" + description = "" + items = [] + oneSided = false + showAvatars = false + showMetadata = false + ariaLabel = "Conversation" + variant = "default" + class = "" + } + + functions { + function messageDirection(item) { + return item.direction === "outgoing" ? "outgoing" : "incoming" + } + + function selectMessage(item, index) { + $emit("messageClick", { + item: item, + index: index, + direction: messageDirection(item) + }) + } + + function selectAvatar(sourceEvent, item, index) { + sourceEvent.stopPropagation() + $emit("avatarClick", { + item: item, + index: index, + direction: messageDirection(item) + }) + } + + function selectLink(sourceEvent, link, item, index) { + sourceEvent.stopPropagation() + $emit("linkClick", { + link: link, + item: item, + index: index + }) + } + + function selectAction(sourceEvent, item, index) { + sourceEvent.stopPropagation() + $emit("action", { + action: item.action || "retry", + item: item, + index: index + }) + } + } + + view { +
+ {#if title || description} +
+ {#if title}

{title}

{/if} + {#if description}

{description}

{/if} +
+ {/if} + + {#if items.length} +
+ {#each items as item, index} +
+
+ {#if showAvatars && (item.avatarSrc || item.avatarFallback)} + + {/if} + +
+ {#if item.title}

{item.title}

{/if} + {#if item.text}

{item.text}

{/if} + {#if item.bullets && item.bullets.length} +
    + {#each item.bullets as bullet}
  • {bullet}
  • {/each} +
+ {/if} + {#if item.links && item.links.length} + + {/if} +
+
+ + {#if showMetadata && (item.timestamp || item.status || item.actionLabel)} +
+ {#if item.statusIcon}{/if} + {#if item.status}{item.status}{/if} + {#if item.timestamp}{/if} + {#if item.actionLabel} + + {/if} +
+ {/if} +
+ {/each} +
+ {/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Checkbox.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Checkbox.wrn new file mode 100644 index 00000000..b945892e --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Checkbox.wrn @@ -0,0 +1,173 @@ +component Checkbox { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Checkbox" + hiddenLabel = false + placeholder = "" + variant = "normal" + icon = "" + iconPosition = "start" + value = "on" + values = [] + options = [] + checked = false + indeterminate = false + orientation = "vertical" + card = false + rightAligned = false + list = false + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { checked: sourceEvent.currentTarget.checked, value: sourceEvent.currentTarget.value, values: values, name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
+ {#if options.length || cornerHint} + + {label} + + {#if cornerHint} + + {cornerHint} + + {/if} + {/if} +
+ {#if options.length} +
+ {#each options as option} + + {/each} +
+ {:else} +
+ +
+ {/if} + {#if helperText} + + {helperText} + + {/if} + + {error} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Clipboard.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Clipboard.wrn new file mode 100644 index 00000000..09893a4a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Clipboard.wrn @@ -0,0 +1,22 @@ +component Clipboard { + props { + @event copy = function + @event success = function + @event error = function + size = "default" + color = "primary" + title = "Clipboard" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Collapse.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Collapse.wrn new file mode 100644 index 00000000..531c31f1 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Collapse.wrn @@ -0,0 +1,95 @@ +component Collapse { + props { + @event toggle = function + @event open = function + @event close = function + size = "default" + color = "primary" + items = [] + multiple = false + mode = "panel" + initialOpenIndexes = [] + ariaLabel = "Collapsible content" + class = "" + } + + state openIndexes = initialOpenIndexes + + functions { + function isOpen(index) { + return openIndexes.includes(index) + } + + function toggleItem(index, item, opening) { + if (item.disabled) { + return + } + opening = !isOpen(index) + if (opening) { + if (multiple) { + openIndexes = openIndexes.concat(index) + } else { + openIndexes = [index] + } + $emit("open", { index: index, item: item }) + } else { + openIndexes = openIndexes.filter((openIndex) => openIndex !== index) + $emit("close", { index: index, item: item }) + } + $emit("toggle", { + index: index, + item: item, + open: opening, + openIndexes: openIndexes + }) + } + } + + view { +
+ {#each items as item, index} +
+ {#if mode === "inline" && item.preview} +

{item.preview}

+ {/if} + + + +
+
+ {#if item.title}

{item.title}

{/if} + {#if item.content}

{item.content}

{/if} + {#if item.links && item.links.length} + + {/if} +
+
+
+ {/each} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ColorPicker.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ColorPicker.wrn new file mode 100644 index 00000000..0ba19a3a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ColorPicker.wrn @@ -0,0 +1,38 @@ +component ColorPicker { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Color" + hiddenLabel = false + placeholder = "" + value = "#2563eb" + icon = "" + iconPosition = "start" + helperText = "" + cornerHint = "" + error = "" + inline = false + variant = "normal" + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
{#if icon}{/if}{value}
+ {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Columns.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Columns.wrn new file mode 100644 index 00000000..96ac7ad1 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Columns.wrn @@ -0,0 +1,35 @@ +component Columns { + props { + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + + view { +
+ +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Combobox.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Combobox.wrn new file mode 100644 index 00000000..7f82992b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Combobox.wrn @@ -0,0 +1,386 @@ +component ComboBox { + props { + size = "default" + color = "primary" + label = "ComboBox" + name = "" + value = "" + options = [] + groups = [] + placeholder = "Search or select an option" + searchPlaceholder = "Start typing…" + clearable = true + allowCustomValue = false + disabled = false + required = false + invalid = false + validationMessage = "" + helpText = "" + loading = false + loadingLabel = "Loading suggestions…" + emptyLabel = "No matching options" + clearLabel = "Clear value" + toggleLabel = "Toggle suggestions" + searchMode = "contains" + searchFields = "label,description" + minSearchLength = 0 + searchResultLimit = 0 + optionTemplate = "default" + defaultOpen = false + closeOnSelect = true + fixed = false + placement = "bottom" + autocomplete = "off" + remote = false + remoteUrl = "" + remoteQueryParam = "q" + remoteDebounce = 250 + remoteAutoLoad = true + infinite = false + hasMore = false + page = 1 + loadMoreLabel = "Load more" + class = "" + @event search = function + @event select = function + @event change = function + @event clear = function + @event open = function + @event close = function + @event load = function + @event error = function + } + + state open = defaultOpen + state query = "" + state selectedValue = value + state activeIndex = -1 + + functions { + function allOptions() { + return [...groups.flatMap((group) => group.options || []), ...options] + } + + function searchableText(option) { + return ((option.label || "") + " " + (option.description || "")).toLowerCase() + } + + function matches(option) { + if (!query || query.length < minSearchLength) { + return true + } + if (searchMode === "startsWith") { + return searchableText(option).startsWith(query.toLowerCase()) + } + if (searchMode === "exact") { + return searchableText(option) === query.toLowerCase() + } + return searchableText(option).includes(query.toLowerCase()) + } + + function matchingOptions(list) { + return list.filter((option) => matches(option)) + } + + function visibleOptions(list) { + if (searchResultLimit > 0) { + return matchingOptions(list).slice(0, searchResultLimit) + } + return matchingOptions(list) + } + + function flatVisibleOptions() { + return visibleOptions(allOptions()) + } + + function isSelected(option) { + return selectedValue === option.value + } + + function selectedOptions() { + return allOptions().filter((option) => isSelected(option)) + } + + function selectedText() { + return selectedOptions().length ? selectedOptions()[0].label : selectedValue + } + + function inputText() { + return query || selectedText() + } + + function shouldShowDropdown() { + if (!open) { + return false + } + if (loading) { + return true + } + if (remote && query.length !== 0 && query.length < minSearchLength) { + return true + } + if (flatVisibleOptions().length) { + return true + } + return infinite && hasMore + } + + function canSelect(option) { + return !option.disabled + } + + function chooseOption(option) { + if (!canSelect(option)) { + return + } + selectedValue = option.value + query = option.label + activeIndex = optionIndex(option) + if (closeOnSelect) { + open = false + } + } + + function updateQuery(event) { + query = event.target.value + selectedValue = allowCustomValue ? event.target.value : "" + open = true + activeIndex = flatVisibleOptions().length ? 0 : -1 + } + + function clearValue(event) { + if (event) { + event.stopPropagation() + } + query = "" + selectedValue = "" + activeIndex = -1 + open = false + } + + function openDropdown() { + if (!disabled) { + open = true + activeIndex = flatVisibleOptions().length ? 0 : -1 + } + } + + function closeDropdown() { + open = false + } + + function toggle() { + if (open) { + closeDropdown() + } else { + openDropdown() + } + } + + function setValue(nextValue) { + selectedValue = nextValue + query = "" + } + + function moveActive(direction) { + if (!flatVisibleOptions().length) { + return + } + activeIndex = (activeIndex + direction + flatVisibleOptions().length) % flatVisibleOptions().length + } + + function handleKeydown(event) { + if (disabled) { + return + } + if (event.key === "ArrowDown") { + event.preventDefault() + openDropdown() + moveActive(1) + } else if (event.key === "ArrowUp") { + event.preventDefault() + openDropdown() + moveActive(-1) + } else if (event.key === "Enter" && open && activeIndex >= 0) { + event.preventDefault() + chooseOption(flatVisibleOptions()[activeIndex]) + } else if (event.key === "Escape") { + closeDropdown() + } else if (event.key === "Home" && open) { + event.preventDefault() + activeIndex = 0 + } else if (event.key === "End" && open) { + event.preventDefault() + activeIndex = flatVisibleOptions().length - 1 + } + } + + function optionIndex(option) { + return flatVisibleOptions().findIndex((item) => item.value === option.value) + } + } + + view { +
+ + +
+ + + + + +
+ +
+
Enter at least {minSearchLength} characters.
+
+ + {loadingLabel} +
+ +
+ {#each groups as group} + {#if visibleOptions(group.options || []).length} +
+
{group.label}
+ {#each group.options || [] as option} + + {/each} +
+ {/if} + {/each} + + {#each options as option} + + {/each} +
+ + +
+ + {#if !allowCustomValue} + + {/if} + + {#if helpText && !validationMessage}{helpText}{/if} + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Confetti.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Confetti.wrn new file mode 100644 index 00000000..26bbf788 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Confetti.wrn @@ -0,0 +1,21 @@ +component Confetti { + props { + @event start = function + @event complete = function + size = "default" + color = "primary" + title = "Confetti" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Container.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Container.wrn new file mode 100644 index 00000000..bcc3a50f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Container.wrn @@ -0,0 +1,46 @@ +component Container { + props { + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + + view { +
+ +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ContextMenu.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ContextMenu.wrn new file mode 100644 index 00000000..7a8b1264 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ContextMenu.wrn @@ -0,0 +1,22 @@ +component ContextMenu { + props { + @event open = function + @event close = function + @event select = function + size = "default" + color = "primary" + title = "Context Menu" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { +
+
{title}
+ {#if description}

{description}

{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/CopyMarkup.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/CopyMarkup.wrn new file mode 100644 index 00000000..ab506a30 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/CopyMarkup.wrn @@ -0,0 +1,23 @@ +component CopyMarkup { + props { + @event copy = function + @event success = function + @event error = function + size = "default" + color = "primary" + label = "Copy Markup" + name = "" + value = "" + placeholder = "" + type = "text" + min = "" + max = "" + step = "" + disabled = false + required = false + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/CustomScrollbar.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/CustomScrollbar.wrn new file mode 100644 index 00000000..37ace07c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/CustomScrollbar.wrn @@ -0,0 +1,14 @@ +component CustomScrollbar { + props { + @event scroll = function + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + view { +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DataMap.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DataMap.wrn new file mode 100644 index 00000000..49a30b5e --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DataMap.wrn @@ -0,0 +1,21 @@ +component DataMap { + props { + @event select = function + @event change = function + size = "default" + color = "primary" + title = "Data Map" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DataTable.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DataTable.wrn new file mode 100644 index 00000000..3ff347ea --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DataTable.wrn @@ -0,0 +1,19 @@ +component DataTable { + props { + @event sort = function + @event select = function + @event change = function + @event rowClick = function + @event pageChange = function + size = "default" + color = "primary" + caption = "Data Table" + columns = [] + rows = [] + striped = true + class = "" + } + view { +
{#each columns as column}{/each}{#each rows as row}{#each columns as column}{/each}{/each}
{caption}
{column.label}
{row[column.key]}
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DatePicker.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DatePicker.wrn new file mode 100644 index 00000000..b7682e5f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DatePicker.wrn @@ -0,0 +1,59 @@ +component DatePicker { + props { + @event input = function + @event change = function + @event open = function + @event close = function + @event focus = function + @event blur = function + @event invalid = function + size = "default" + color = "primary" + label = "Date Picker" + id = "" + name = "" + value = "" + placeholder = "" + type = "date" + locale = "en-US" + firstDayOfWeek = 0 + months = [{ label: "Jan", value: "01" }, { label: "Feb", value: "02" }, { label: "Mar", value: "03" }, { label: "Apr", value: "04" }, { label: "May", value: "05" }, { label: "Jun", value: "06" }, { label: "Jul", value: "07" }, { label: "Aug", value: "08" }, { label: "Sep", value: "09" }, { label: "Oct", value: "10" }, { label: "Nov", value: "11" }, { label: "Dec", value: "12" }] + days = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31] + years = [2024, 2025, 2026, 2027, 2028, 2029, 2030] + min = "" + max = "" + step = "" + helperText = "" + cornerHint = "" + error = "" + variant = "normal" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + state currentValue = value + state selectedYear = value ? value.split("-")[0] : "" + state selectedMonth = value ? value.split("-")[1] : "" + state selectedDay = value ? value.split("-")[2] : "" + state expanded = false + functions { + function openCalendar(sourceEvent) { expanded = true; $emit("open", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function updateDate(part, nextValue, sourceEvent, nextDate, detail) { if (part === "year") { selectedYear = String(nextValue) } if (part === "month") { selectedMonth = String(nextValue).padStart(2, "0") } if (part === "day") { selectedDay = String(nextValue).padStart(2, "0") } if (!selectedYear || !selectedMonth || !selectedDay) { return } nextDate = selectedYear + "-" + selectedMonth + "-" + selectedDay; if ((min && nextDate < min) || (max && nextDate > max)) { return } currentValue = nextDate; detail = { value: currentValue, year: selectedYear, month: selectedMonth, day: selectedDay, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function finishDate(sourceEvent) { if (!currentValue) { return } expanded = false; $emit("close", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function selectDay(sourceEvent, root, input, nextDate, trigger, detail) { root = sourceEvent.currentTarget.closest(".wire-next--date-picker"); input = root.querySelector(".wire-next__picker-value"); nextDate = input.getAttribute("value").slice(0, 5) + root.querySelector("select").getAttribute("value") + "-" + sourceEvent.currentTarget.dataset.value; currentValue = nextDate; input.setAttribute("value", nextDate); trigger = root.querySelector(".wire-next__date-trigger span"); if (trigger) { trigger.replaceChildren(nextDate) } sourceEvent.currentTarget.setAttribute("aria-pressed", "true"); detail = { value: nextDate, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function clearDate(sourceEvent, detail) { if (disabled || readonly) { return } currentValue = ""; detail = { value: currentValue, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function handleFocus(sourceEvent) { $emit("focus", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleBlur(sourceEvent) { $emit("blur", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleInvalid(sourceEvent) { $emit("invalid", { name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
{#if currentValue && !readonly && !disabled}{/if}
+ + {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DeviceFrame.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DeviceFrame.wrn new file mode 100644 index 00000000..f2d3d891 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DeviceFrame.wrn @@ -0,0 +1,31 @@ +component DeviceFrame { + props { + @event change = function + @event rotate = function + size = "default" + color = "primary" + title = "Device Frame" + description = "" + items = [] + variant = "default" + device = "phone" + orientation = "portrait" + src = "" + srcdoc = "" + frameTitle = "Device preview" + showToolbar = true + allow = "" + class = "" + } + state currentOrientation = orientation + functions { + function setDevice(nextDevice, sourceEvent) { $emit("change", { device: nextDevice, orientation: currentOrientation, sourceEvent: sourceEvent }) } + function rotateFrame(sourceEvent) { currentOrientation = currentOrientation === "portrait" ? "landscape" : "portrait"; $emit("rotate", { device: device, orientation: currentOrientation, sourceEvent: sourceEvent }); $emit("change", { device: device, orientation: currentOrientation, sourceEvent: sourceEvent }) } + } + view { +
+
{#if title}{title}{/if}{#if description}

{description}

{/if}
{#if showToolbar}{/if}
+
{#if src || srcdoc}{:else}
{/if}
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Divider.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Divider.wrn new file mode 100644 index 00000000..b7a19a9f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Divider.wrn @@ -0,0 +1,69 @@ +component Divider { + props { + size = "default" + color = "primary" + label = "" + orientation = "horizontal" + class = "" + } + + view { +
+ {#if orientation === "vertical"} + + {:else} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DragAndDrop.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DragAndDrop.wrn new file mode 100644 index 00000000..944dec48 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/DragAndDrop.wrn @@ -0,0 +1,25 @@ +component DragAndDrop { + props { + @event dragStart = function + @event dragEnd = function + @event dragEnter = function + @event dragLeave = function + @event drop = function + @event change = function + size = "default" + color = "primary" + title = "Drag And Drop" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Drawer.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Drawer.wrn new file mode 100644 index 00000000..641cef87 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Drawer.wrn @@ -0,0 +1,21 @@ +component Drawer { + props { + @event open = function + @event close = function + size = "default" + color = "primary" + title = "Drawer" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Dropdown.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Dropdown.wrn new file mode 100644 index 00000000..f73c1a6c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Dropdown.wrn @@ -0,0 +1,53 @@ +component Dropdown { + props { + @event toggle = function + @event open = function + @event close = function + @event select = function + size = "default" + color = "primary" + label = "Open menu" + items = [] + placement = "end" + class = "" + } + + functions { + function toggleMenu(event) { + $emit("toggle", { open: event.currentTarget.open }) + $emit(event.currentTarget.open ? "open" : "close", { source: "trigger" }) + } + + function selectItem(item) { + $emit("select", { item: item, value: item.value || "" }) + } + } + + view { +
+ + + + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FeatureCard.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FeatureCard.wrn new file mode 100644 index 00000000..93eb1906 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FeatureCard.wrn @@ -0,0 +1,113 @@ +component FeatureCard { + props { + icon = "" + title = "Feature" + description = "" + href = "" + actionLabel = "Learn more" + actionIcon = "" + badge = "" + badgeColor = "primary" + size = "default" + color = "primary" + variant = "default" + hover = "lift" + align = "left" + disabled = false + class = "" + } + + view { +
+
+
+ + {#if icon} + + {/if} +
+ + {#if badge} + + {/if} +
+ +

+ {title} +

+ + {#if description} +

+ {description} +

+ {/if} + + + +
+ + + {#if href && actionLabel} + + {/if} +
+ + {#if href} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FeatureGrid.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FeatureGrid.wrn new file mode 100644 index 00000000..cec10f97 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FeatureGrid.wrn @@ -0,0 +1,55 @@ +component FeatureGrid { + props { + color = "primary" + size = "default" + columns = 3 + tabletColumns = 2 + mobileColumns = 1 + gap = "md" + minItemWidth = "" + equalHeight = true + align = "stretch" + maxWidth = "full" + class = "" + } + + view { +
+ +
+ } + + style { + .wire-feature-grid-autofit { + grid-template-columns: repeat(auto-fit, minmax(var(--wire-feature-grid-min), 1fr)); + } + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FeatureIconCard.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FeatureIconCard.wrn new file mode 100644 index 00000000..1b985d39 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FeatureIconCard.wrn @@ -0,0 +1,78 @@ +component FeatureIconCard { + props { + icon = "icon-[lucide--sparkles]" + iconSize = "md" + iconVariant = "soft" + title = "Feature" + description = "" + href = "" + actionLabel = "Explore" + badge = "" + size = "default" + color = "primary" + variant = "default" + align = "left" + hover = "lift" + class = "" + } + + view { +
+
+ + + {#if badge} + + {badge} + + {/if} +
+ +

{title}

+ + {#if description} +

{description}

+ {/if} + + + + {#if href} + + {/if} + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FileInput.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FileInput.wrn new file mode 100644 index 00000000..b3ed2183 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FileInput.wrn @@ -0,0 +1,52 @@ +component FileInput { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event select = function + @event clear = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "File" + hiddenLabel = false + placeholder = "Choose a file" + value = "" + icon = "icon-[lucide--upload]" + iconPosition = "start" + accept = "" + multiple = false + helperText = "" + cornerHint = "" + error = "" + inline = false + variant = "normal" + readonly = false + disabled = false + required = false + class = "" + } + state selectedName = "" + functions { + function handleChange(sourceEvent) { + sourceEvent.stopPropagation() + selectedName = sourceEvent.currentTarget.files && sourceEvent.currentTarget.files.length ? sourceEvent.currentTarget.files[0].name : "" + $emit("input", { files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent }) + $emit("change", { files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent }) + if (selectedName) $emit("select", { files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent }) + else $emit("clear", { name: name, sourceEvent: sourceEvent }) + } + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
{#if icon}{/if}{selectedName || value || placeholder}
+ {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FileUpload.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FileUpload.wrn new file mode 100644 index 00000000..207d3571 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FileUpload.wrn @@ -0,0 +1,26 @@ +component FileUpload { + props { + @event select = function + @event upload = function + @event progress = function + @event success = function + @event error = function + @event cancel = function + @event remove = function + size = "default" + color = "primary" + title = "File Upload" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FileUploadProgress.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FileUploadProgress.wrn new file mode 100644 index 00000000..329a5859 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/FileUploadProgress.wrn @@ -0,0 +1,37 @@ +component FileUploadProgress { + props { + @event cancel = function + @event retry = function + @event complete = function + size = "default" + color = "primary" + label = "Progress" + value = 50 + max = 100 + showValue = true + fileName = "" + fileSize = "" + uploadedSize = "" + status = "uploading" + cancelLabel = "Cancel upload" + retryLabel = "Retry upload" + class = "" + } + state currentValue = value + state currentStatus = status + functions { + function percent() { if (!Number(max)) { return 0 } return Math.max(0, Math.min(100, Math.round(Number(currentValue) / Number(max) * 100))) } + function detail(sourceEvent) { return { value: currentValue, max: max, percent: percent(), status: currentStatus, fileName: fileName, sourceEvent: sourceEvent } } + function cancelUpload(sourceEvent) { currentStatus = "cancelled"; $emit("cancel", detail(sourceEvent)) } + function retryUpload(sourceEvent) { currentValue = 0; currentStatus = "uploading"; $emit("retry", detail(sourceEvent)) } + function completeUpload(sourceEvent) { currentValue = max; currentStatus = "complete"; $emit("complete", detail(sourceEvent)) } + } + view { +
+
{#if fileName}{fileName}{#if uploadedSize || fileSize}{uploadedSize}{#if uploadedSize && fileSize} of {/if}{fileSize}{:else}{label}{/if}{:else}{label}{/if}{#if showValue}{percent()}%{/if}
+ +
{#if currentStatus === "uploading"}Uploading securely…{:else if currentStatus === "complete"}Upload complete{:else if currentStatus === "error"}Upload failed{:else}Upload cancelled{/if}
+
{#if currentStatus === "uploading"}{/if}{#if currentStatus === "error" || currentStatus === "cancelled"}{/if}
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Footer.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Footer.wrn new file mode 100644 index 00000000..e0f3ac1d --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Footer.wrn @@ -0,0 +1,144 @@ +component Footer { + props { + @event select = function + @event action = function + size = "default" + color = "primary" + label = "Footer navigation" + items = [] + columns = 3 + maxWidth = "compact" + copyright = "" + class = "" + } + + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Grid.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Grid.wrn new file mode 100644 index 00000000..b76a5447 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Grid.wrn @@ -0,0 +1,40 @@ +component Grid { + props { + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + + view { +
+ +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Hero.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Hero.wrn new file mode 100644 index 00000000..7613a2b6 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Hero.wrn @@ -0,0 +1,149 @@ +component Hero { + props { + eyebrow = "" + title = "Build something remarkable" + highlight = "" + description = "" + align = "left" + size = "default" + color = "primary" + variant = "default" + primaryLabel = "" + primaryHref = "" + primaryIcon = "" + secondaryLabel = "" + secondaryHref = "" + secondaryIcon = "" + tertiaryLabel = "" + tertiaryHref = "" + badges = [] + trustItems = [] + maxWidth = "xl" + class = "" + } + + view { +
+
+ {#if variant === "gradient"} + + {/if} + +
+ + + {#if eyebrow} +
+ + {eyebrow} +
+ {/if} + +

+ {title} + {#if highlight} + + {highlight} + + {/if} +

+ + {#if description} +

+ {description} +

+ {/if} + + {#if badges.length > 0} +
+ {#each badges as badge} + + {/each} +
+ {/if} + +
+ + + +
+ + {#if trustItems.length > 0} +
+ {#each trustItems as item} + + + {item.label || item.title || item} + + {/each} +
+ {/if} + + + +
+ +
+ +
+ + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/HeroActions.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/HeroActions.wrn new file mode 100644 index 00000000..28b0cc44 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/HeroActions.wrn @@ -0,0 +1,52 @@ +component HeroActions { + props { + actions = [] + align = "left" + orientation = "horizontal" + stackOnMobile = true + fullWidthMobile = true + size = "default" + color = "primary" + class = "" + } + + view { +
+ {#each actions as action, index} + {#if action.label} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Image.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Image.wrn new file mode 100644 index 00000000..881d5229 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Image.wrn @@ -0,0 +1,47 @@ +component Image { + props { + size = "default" + color = "primary" + src = "" + alt = "" + width = "" + height = "" + loading = "lazy" + rounded = false + class = "" + } + + view { +
+ {#if src} + {alt} + {:else} + + {/if} + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Input.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Input.wrn new file mode 100644 index 00000000..3e12c986 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Input.wrn @@ -0,0 +1,92 @@ +component Input { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event invalid = function + @event keydown = function + @event keyup = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Input" + hiddenLabel = false + placeholder = "" + value = "" + type = "text" + variant = "normal" + icon = "" + iconPosition = "start" + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + autocomplete = "" + inputmode = "" + minlength = "" + maxlength = "" + pattern = "" + min = "" + max = "" + step = "" + class = "" + } + functions { + function detail(sourceEvent) { + return { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent } + } + function handleInput(sourceEvent) { sourceEvent.stopPropagation(); $emit("input", detail(sourceEvent)) } + function handleChange(sourceEvent) { sourceEvent.stopPropagation(); $emit("change", detail(sourceEvent)) } + function handleFocus(sourceEvent) { sourceEvent.stopPropagation(); $emit("focus", detail(sourceEvent)) } + function handleBlur(sourceEvent) { sourceEvent.stopPropagation(); $emit("blur", detail(sourceEvent)) } + function handleInvalid(sourceEvent) { sourceEvent.stopPropagation(); $emit("invalid", { value: sourceEvent.currentTarget.value, name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } + function handleKeydown(sourceEvent) { sourceEvent.stopPropagation(); $emit("keydown", { key: sourceEvent.key, value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + function handleKeyup(sourceEvent) { sourceEvent.stopPropagation(); $emit("keyup", { key: sourceEvent.key, value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + } + view { +
+
+ + {#if cornerHint}{cornerHint}{/if} +
+
+ {#if icon}{/if} + + {#if variant === "floating"}{label}{/if} +
+ {#if helperText}{helperText}{/if} + {error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/InputGroup.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/InputGroup.wrn new file mode 100644 index 00000000..aea3fd7a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/InputGroup.wrn @@ -0,0 +1,51 @@ +component InputGroup { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event submit = function + @event action = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Input group" + hiddenLabel = false + value = "" + placeholder = "" + type = "text" + startText = "" + endText = "" + icon = "" + iconPosition = "start" + actionLabel = "" + helperText = "" + cornerHint = "" + error = "" + inline = false + variant = "normal" + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + function handleKeydown(sourceEvent) { if (sourceEvent.key === "Enter") { sourceEvent.stopPropagation(); $emit("submit", { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } } + function handleAction(sourceEvent) { $emit("action", { name: name, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if startText}{startText}{/if} + {#if icon}{/if} + + {#if endText}{endText}{/if} + {#if actionLabel}{/if} +
+ {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/InputNumber.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/InputNumber.wrn new file mode 100644 index 00000000..226922fd --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/InputNumber.wrn @@ -0,0 +1,623 @@ +component InputNumber { + props { + size = "default" + color = "primary" + variant = "default" + class = "" + + id = "" + name = "quantity" + value = 0 + min = "" + max = "" + step = 1 + precision = "auto" + + label = "" + description = "" + helpText = "" + error = "" + invalid = false + + prefix = "" + suffix = "" + placeholder = "" + autocomplete = "off" + inputMode = "decimal" + ariaLabel = "" + + required = false + disabled = false + inputDisabled = false + buttonsDisabled = false + readonly = false + allowInput = true + keyboard = true + wheel = false + clamp = true + fullWidth = false + showButtons = true + showValidationMessage = true + + decrementLabel = "Decrease value" + incrementLabel = "Increase value" + controlsLabel = "Quantity controls" + requiredMessage = "A value is required." + minMessage = "Value is below the minimum." + maxMessage = "Value is above the maximum." + + @event input = function + @event change = function + @event increment = function + @event decrement = function + } + + state currentValue = value + state committedValue = value + + functions { + function inputId() { + if (id !== "") { + return id + } + + if (name !== "") { + return name + } + + return "input-number" + } + + function descriptionId() { + return inputId() + "-description" + } + + function messageId() { + return inputId() + "-message" + } + + function componentColor() { + if (color === "secondary") { + return "var(--wire-color-secondary)" + } + + if (color === "success") { + return "var(--wire-color-success)" + } + + if (color === "warning") { + return "var(--wire-color-warning)" + } + + if (color === "danger") { + return "var(--wire-color-danger)" + } + + if (color === "info") { + return "var(--wire-color-info)" + } + + return "var(--wire-color-primary)" + } + + function hasMin() { + return min !== "" && min !== null && min !== undefined + } + + function hasMax() { + return max !== "" && max !== null && max !== undefined + } + + function isBlank() { + return currentValue === "" || currentValue === null || currentValue === undefined + } + + function normalizedStep() { + return Number(step) > 0 ? Number(step) : 1 + } + + function inferredPrecision() { + if (precision !== "auto" && precision !== "") { + return Math.max(0, Number(precision) || 0) + } + + if (String(normalizedStep()).includes(".")) { + return String(normalizedStep()).split(".")[1].length + } + + return 0 + } + + function precisionFactor() { + return Math.pow(10, inferredPrecision()) + } + + function roundValue(nextValue) { + return Math.round(Number(nextValue) * precisionFactor()) / precisionFactor() + } + + function clampValue(nextValue) { + nextValue = Number(nextValue) + + if (hasMin() && nextValue < Number(min)) { + nextValue = Number(min) + } + + if (hasMax() && nextValue > Number(max)) { + nextValue = Number(max) + } + + return roundValue(nextValue) + } + + function isBelowMin() { + return !isBlank() && hasMin() && Number(currentValue) < Number(min) + } + + function isAboveMax() { + return !isBlank() && hasMax() && Number(currentValue) > Number(max) + } + + function isInvalid() { + return ( + invalid || + error !== "" || + (required && isBlank()) || + isBelowMin() || + isAboveMax() + ) + } + + function validationMessage() { + if (error !== "") { + return error + } + + if (required && isBlank()) { + return requiredMessage + } + + if (isBelowMin()) { + return minMessage + } + + if (isAboveMax()) { + return maxMessage + } + + return "" + } + + function hasMessage() { + return ( + helpText !== "" || + (showValidationMessage && isInvalid() && validationMessage() !== "") + ) + } + + function describedBy() { + if (description !== "" && hasMessage()) { + return descriptionId() + " " + messageId() + } + + if (description !== "") { + return descriptionId() + } + + if (hasMessage()) { + return messageId() + } + + return "" + } + + function decrementDisabled() { + return ( + disabled || + readonly || + buttonsDisabled || + (hasMin() && !isBlank() && Number(currentValue) <= Number(min)) + ) + } + + function incrementDisabled() { + return ( + disabled || + readonly || + buttonsDisabled || + (hasMax() && !isBlank() && Number(currentValue) >= Number(max)) + ) + } + + function dispatchInputNumberEvent( + sourceEvent, + eventName, + action, + previousValue, + root, + customEvent + ) { + root = sourceEvent.currentTarget.closest("[data-wrn-input-number]") + + if (!root && sourceEvent.target) { + root = sourceEvent.target.closest("[data-wrn-input-number]") + } + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent(eventName, true, false, { + component: "InputNumber", + name: name, + value: currentValue, + previousValue: previousValue, + action: action, + min: hasMin() ? Number(min) : null, + max: hasMax() ? Number(max) : null, + step: normalizedStep(), + valid: !isInvalid() + }) + root.dispatchEvent(customEvent) + } + + function applyControlValue(nextValue, action, sourceEvent, previousValue) { + previousValue = currentValue + currentValue = clampValue(nextValue) + committedValue = currentValue + + dispatchInputNumberEvent( + sourceEvent, + "input", + action, + previousValue + ) + dispatchInputNumberEvent( + sourceEvent, + "change", + action, + previousValue + ) + dispatchInputNumberEvent( + sourceEvent, + action, + action, + previousValue + ) + } + + function incrementValue(sourceEvent, nextValue) { + if (incrementDisabled()) { + return + } + + if (isBlank()) { + nextValue = hasMin() ? Number(min) : normalizedStep() + } else { + nextValue = + Number(currentValue) + + normalizedStep() * (sourceEvent.shiftKey ? 10 : 1) + } + + applyControlValue(nextValue, "increment", sourceEvent) + } + + function decrementValue(sourceEvent, nextValue) { + if (decrementDisabled()) { + return + } + + if (isBlank()) { + nextValue = hasMax() ? Number(max) : -normalizedStep() + } else { + nextValue = + Number(currentValue) - + normalizedStep() * (sourceEvent.shiftKey ? 10 : 1) + } + + applyControlValue(nextValue, "decrement", sourceEvent) + } + + function handleInput(sourceEvent, previousValue, nextValue) { + sourceEvent.stopPropagation() + previousValue = currentValue + nextValue = sourceEvent.target.value + + if (nextValue === "") { + currentValue = "" + } else if (!Number.isNaN(Number(nextValue))) { + currentValue = roundValue(Number(nextValue)) + } + + dispatchInputNumberEvent( + sourceEvent, + "input", + "input", + previousValue + ) + } + + function handleChange(sourceEvent, previousValue) { + sourceEvent.stopPropagation() + previousValue = committedValue + + if (!isBlank()) { + currentValue = clamp + ? clampValue(currentValue) + : roundValue(currentValue) + } + + committedValue = currentValue + + dispatchInputNumberEvent( + sourceEvent, + "change", + "change", + previousValue + ) + } + + function handleKeydown(sourceEvent) { + if ( + !keyboard || + disabled || + readonly || + inputDisabled || + !allowInput + ) { + return + } + + if (sourceEvent.key === "ArrowUp") { + sourceEvent.preventDefault() + incrementValue(sourceEvent) + } else if (sourceEvent.key === "ArrowDown") { + sourceEvent.preventDefault() + decrementValue(sourceEvent) + } else if (sourceEvent.key === "Home" && hasMin()) { + sourceEvent.preventDefault() + applyControlValue(Number(min), "decrement", sourceEvent) + } else if (sourceEvent.key === "End" && hasMax()) { + sourceEvent.preventDefault() + applyControlValue(Number(max), "increment", sourceEvent) + } + } + + function handleWheel(sourceEvent) { + if ( + !wheel || + disabled || + readonly || + inputDisabled || + !allowInput + ) { + return + } + + sourceEvent.preventDefault() + + if (sourceEvent.deltaY < 0) { + incrementValue(sourceEvent) + } else if (sourceEvent.deltaY > 0) { + decrementValue(sourceEvent) + } + } + } + + view { +
+ {#if label !== "" && variant !== "labeled" && variant !== "seat"} + + {/if} + + {#if description !== "" && variant !== "labeled" && variant !== "seat"} +

+ {description} +

+ {/if} + +
+ {#if variant === "horizontal" && showButtons} + + {/if} + +
+ {#if variant === "labeled" || variant === "seat"} +
+ {#if label !== ""} + + {/if} + + {#if description !== ""} + + {description} + + {/if} +
+ {/if} + +
+ {#if prefix !== ""} + + {/if} + + + + {#if suffix !== ""} + + {/if} +
+
+ + {#if variant === "horizontal" && showButtons} + + {:else} + {#if showButtons} +
+ + + +
+ {/if} + {/if} +
+ + {#if showValidationMessage && isInvalid() && validationMessage() !== ""} + + {/if} + + {#if (!showValidationMessage || !isInvalid() || validationMessage() === "") && helpText !== ""} +

+ {helpText} +

+ {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Kbd.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Kbd.wrn new file mode 100644 index 00000000..e14edc4c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Kbd.wrn @@ -0,0 +1,9 @@ +component Kbd { + props { + size = "default" + color = "primary" + label = "⌘ K" + class = "" + } + view { {label} } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/LayoutSplitter.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/LayoutSplitter.wrn new file mode 100644 index 00000000..f9ad4d58 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/LayoutSplitter.wrn @@ -0,0 +1,16 @@ +component LayoutSplitter { + props { + @event resizeStart = function + @event resize = function + @event resizeEnd = function + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + view { +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/LegendIndicator.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/LegendIndicator.wrn new file mode 100644 index 00000000..1fae3791 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/LegendIndicator.wrn @@ -0,0 +1,21 @@ +component LegendIndicator { + props { + @event toggle = function + @event select = function + size = "default" + color = "primary" + title = "Legend Indicator" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Link.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Link.wrn new file mode 100644 index 00000000..3cf17764 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Link.wrn @@ -0,0 +1,47 @@ +component Link { + props { + size = "default" + color = "primary" + label = "Link" + href = "#" + target = "" + rel = "" + external = false + class = "" + } + + view { + + {label} + + {#if external} + + {/if} + + + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/List.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/List.wrn new file mode 100644 index 00000000..0ac667a7 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/List.wrn @@ -0,0 +1,107 @@ +component List { + props { + size = "default" + color = "primary" + title = "List" + description = "" + items = [] + variant = "default" + class = "" + } + + view { +
+ {#if title || description} +
+ {#if title} +

{title}

+ {/if} + {#if description} +

{description}

+ {/if} +
+ {/if} + + + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ListGroup.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ListGroup.wrn new file mode 100644 index 00000000..35366c9c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ListGroup.wrn @@ -0,0 +1,21 @@ +component ListGroup { + props { + @event select = function + @event change = function + size = "default" + color = "primary" + title = "List Group" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Map.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Map.wrn new file mode 100644 index 00000000..6d0da585 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Map.wrn @@ -0,0 +1,85 @@ +component Map { + props { + size = "default" + color = "primary" + title = "Map" + description = "" + items = [] + variant = "default" + class = "" + } + + view { +
+ {#if title || description} +
+
+ {#if title} +

{title}

+ {/if} + {#if description} +

{description}

+ {/if} +
+ + + +
+ {/if} + +
+ + +
+ +
+ + {#if items.length > 0} + {#each items as item, index} + + {/each} + {/if} + +
+ + +
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/MarketingSectionHeader.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/MarketingSectionHeader.wrn new file mode 100644 index 00000000..5d3d9de3 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/MarketingSectionHeader.wrn @@ -0,0 +1,59 @@ +component MarketingSectionHeader { + props { + id = "" + eyebrow = "" + title = "" + description = "" + align = "split" + size = "default" + color = "primary" + actionLabel = "" + actionHref = "" + actionIcon = "" + actionExternal = false + class = "" + } + + view { +
+ +
+ +
+ +
+ {#if actionLabel} + + {/if} + +
+ + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Marquee.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Marquee.wrn new file mode 100644 index 00000000..53d4ca7b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Marquee.wrn @@ -0,0 +1,111 @@ +component Marquee { + props { + size = "default" + color = "primary" + title = "Marquee" + description = "" + items = [] + variant = "default" + class = "" + } + + state paused = false + + view { +
+
+ {#if title} +
+ + {title} +
+ {/if} + +
+
+ {#each items as item} + + + {item.label || item.title} + {#if item.meta} + {item.meta} + {/if} + + {:empty} +

{description || "No announcements available."}

+ {/each} + + {#if items.length > 0} + {#each items as item} + + {/each} + {/if} +
+
+ + +
+ + +
+ } + + style { + .wire-marquee-track { + animation: wire-marquee 32s linear infinite; + } + + .wire-marquee-paused { + animation-play-state: paused; + } + + @keyframes wire-marquee { + from { transform: translateX(0); } + to { transform: translateX(-50%); } + } + + @media (prefers-reduced-motion: reduce) { + .wire-marquee-track { + animation: none; + } + } + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/MegaMenu.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/MegaMenu.wrn new file mode 100644 index 00000000..303025b0 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/MegaMenu.wrn @@ -0,0 +1,20 @@ +component MegaMenu { + props { + @event open = function + @event close = function + @event select = function + size = "default" + color = "primary" + label = "Mega Menu" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/MetricCard.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/MetricCard.wrn new file mode 100644 index 00000000..efc63fc4 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/MetricCard.wrn @@ -0,0 +1,107 @@ +component MetricCard { + props { + label = "Metric" + value = "0" + description = "" + icon = "" + prefix = "" + suffix = "" + trend = "" + trendLabel = "" + trendDirection = "neutral" + href = "" + actionLabel = "" + size = "default" + color = "primary" + variant = "default" + align = "left" + class = "" + } + + view { +
+
+
+

{label}

+

+ {prefix}{value}{suffix} +

+
+ + {#if icon} + + + + {/if} +
+ + {#if description} +

{description}

+ {/if} + + {#if trend || trendLabel} +
+ + {#if trendDirection === "up" || trendDirection === "positive"} + + {:else if trendDirection === "down" || trendDirection === "negative"} + + {:else} + + {/if} + {trend} + + {#if trendLabel} + {trendLabel} + {/if} +
+ {/if} + + {#if href} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/MetricGrid.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/MetricGrid.wrn new file mode 100644 index 00000000..5e353cff --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/MetricGrid.wrn @@ -0,0 +1,60 @@ +component MetricGrid { + props { + items = [] + columns = 4 + tabletColumns = 2 + mobileColumns = 1 + gap = "md" + equalHeight = true + dividers = false + size = "default" + color = "primary" + variant = "default" + class = "" + } + + view { +
+ {#each items as item} + + {:empty} + + {/each} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Modal.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Modal.wrn new file mode 100644 index 00000000..2366e70f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Modal.wrn @@ -0,0 +1,23 @@ +component Modal { + props { + @event open = function + @event close = function + @event cancel = function + @event confirm = function + size = "default" + color = "primary" + title = "Modal" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Nav.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Nav.wrn new file mode 100644 index 00000000..de980dc7 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Nav.wrn @@ -0,0 +1,19 @@ +component Nav { + props { + @event select = function + @event change = function + size = "default" + color = "primary" + label = "Nav" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Navbar.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Navbar.wrn new file mode 100644 index 00000000..b6f85083 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Navbar.wrn @@ -0,0 +1,140 @@ +component Navbar { + props { + @event toggle = function + @event open = function + @event close = function + @event select = function + @event action = function + size = "default" + color = "primary" + label = "Primary navigation" + topbarLabel = "Utility navigation" + brand = {} + items = [] + actions = [] + active = "" + sticky = false + openOnHover = false + maxWidth = "full" + mobileLabel = "Toggle navigation" + class = "" + } + + state mobileOpen = false + + functions { + function toggleNavigation() { + mobileOpen = !mobileOpen + $emit("toggle", { open: mobileOpen }) + $emit(mobileOpen ? "open" : "close", { source: "mobile" }) + } + + function selectItem(item, level) { + mobileOpen = false + $emit("select", { item: item, value: item.value || "", level: level }) + } + + function selectAction(item) { + mobileOpen = false + $emit("action", { item: item, value: item.value || "" }) + } + + function isItemActive(item) { + if (!item) return false + if (item.value && item.value === active) return true + if (!item.children || !item.children.length) return false + return item.children.some(function (child) { + return isItemActive(child) + }) + } + + function toggleDropdown(event, item) { + $emit(event.currentTarget.open ? "open" : "close", { + source: "menu", + item: item + }) + } + } + + view { +
+
+ +
+ +
+ + {#if brand.logo} + + {/if} + {#if brand.icon} + + {/if} + {#if brand.label || brand.description} + + {#if brand.label}{brand.label}{/if} + {#if brand.description}{brand.description}{/if} + + {/if} + + + + +
+ + +
+ {#each actions as item} + + {#if item.icon}{/if} + {item.label} + + {/each} + +
+
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PageHeader.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PageHeader.wrn new file mode 100644 index 00000000..42132045 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PageHeader.wrn @@ -0,0 +1,105 @@ +component PageHeader { + props { + eyebrow = "" + title = "" + description = "" + icon = "" + align = "left" + size = "default" + compact = false + showBreadcrumbs = false + breadcrumbs = [] + primaryLabel = "" + primaryHref = "" + primaryIcon = "" + secondaryLabel = "" + secondaryHref = "" + secondaryIcon = "" + color = "primary" + variant = "default" + class = "" + } + + view { +
+
+ {#if showBreadcrumbs && breadcrumbs.length > 0} + + {/if} + +
+
+ {#if icon} + + + + {/if} + + + + +
+ +
+ {#if secondaryLabel} +
+
+ + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Pagination.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Pagination.wrn new file mode 100644 index 00000000..afbfc65c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Pagination.wrn @@ -0,0 +1,20 @@ +component Pagination { + props { + @event change = function + @event previous = function + @event next = function + size = "default" + color = "primary" + label = "Pagination" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PinInput.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PinInput.wrn new file mode 100644 index 00000000..8aa45c9e --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PinInput.wrn @@ -0,0 +1,114 @@ +component PinInput { + props { + size = "default" + color = "primary" + label = "Verification code" + name = "pin" + value = "" + length = 4 + pattern = "[0-9]" + type = "text" + inputMode = "numeric" + placeholder = "○" + autocomplete = "one-time-code" + masked = false + disabled = false + readonly = false + required = false + autoFocus = false + autoSubmit = false + allowPaste = true + clearable = true + clearLabel = "Clear code" + separator = "" + groupSize = 0 + helpText = "" + invalid = false + validationMessage = "" + class = "" + @event input = function + @event change = function + @event complete = function + @event paste = function + @event clear = function + @event error = function + } + + functions { + function inputIndexes() { + return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].slice( + 0, + Math.max(1, Math.min(12, Number(length))) + ) + } + } + + view { +
+
+ {label} + +
+ +
+ {#each inputIndexes() as index} + + {#if separator && groupSize !== 0 && (index + 1) % groupSize === 0 && index + 1 !== length} + + {/if} + {/each} +
+ + + + {#if helpText && !validationMessage}{helpText}{/if} + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Popover.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Popover.wrn new file mode 100644 index 00000000..2b196a00 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Popover.wrn @@ -0,0 +1,21 @@ +component Popover { + props { + @event open = function + @event close = function + size = "default" + color = "primary" + title = "Popover" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { +
+
{title}
+ {#if description}

{description}

{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PortalDashboard.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PortalDashboard.wrn new file mode 100644 index 00000000..e8001518 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PortalDashboard.wrn @@ -0,0 +1,98 @@ +component PortalDashboard { + props { + @event action = function + @event navigate = function + size = "default" + color = "primary" + eyebrow = "Overview" + eyebrowKey = "" + title = "Dashboard" + titleKey = "" + description = "" + descriptionKey = "" + userName = "" + metrics = [] + actions = [] + updates = [] + tasks = [] + class = "" + } + + functions { + function chooseAction(item, index) { + $emit("action", { item: item, value: item.value || "", index: index }) + } + + function chooseNavigation(item, index) { + $emit("navigate", { item: item, value: item.value || "", index: index }) + } + } + + view { +
+
+
+ {#if eyebrowKey}{eyebrow}{/if} + {#if !eyebrowKey}{eyebrow}{/if} +

+ {#if titleKey}{title}{/if} + {#if !titleKey}{title}{/if} + {#if userName}, {userName}{/if} +

+ {#if descriptionKey}

{description}

{/if} + {#if !descriptionKey && description}

{description}

{/if} +
+
+
+ +
+ {#each metrics as item} +
+ +
{item.label}{item.value}{#if item.detail}{item.detail}{/if}
+
+ {/each} +
+ +
+
+
Shortcuts

Quick actions

+
+ {#each actions as item, index} + + + {item.label}{#if item.description}{item.description}{/if} + + + {/each} +
+
+ +
+
Priority

Tasks requiring attention

+ +
+ +
+
Latest

Recent updates

+
+ {#each updates as item} +
+ +
{item.label}{#if item.detail}

{item.detail}

{/if}{item.time || ''}
+
+ {/each} +
+
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PreferenceSwitcher.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PreferenceSwitcher.wrn new file mode 100644 index 00000000..29962022 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PreferenceSwitcher.wrn @@ -0,0 +1,82 @@ +component PreferenceSwitcher { + props { + @event theme = function + @event color = function + @event language = function + size = "default" + color = "primary" + themeLabel = "Theme" + colorLabel = "Accent color" + languageLabel = "Language" + languages = [ + {"label": "English", "shortLabel": "EN", "value": "en"}, + {"label": "हिन्दी", "shortLabel": "हि", "value": "hi"}, + {"label": "मराठी", "shortLabel": "म", "value": "mr"} + ] + colors = [ + {"label": "Blue", "value": "blue", "hex": "#2563eb"}, + {"label": "Cyan", "value": "cyan", "hex": "#0891b2"}, + {"label": "Emerald", "value": "emerald", "hex": "#059669"}, + {"label": "Violet", "value": "violet", "hex": "#7c3aed"}, + {"label": "Rose", "value": "rose", "hex": "#e11d48"}, + {"label": "Amber", "value": "amber", "hex": "#d97706"} + ] + compact = true + class = "" + } + + functions { + function choose(type, value) { + $emit(type, { value: value }) + } + } + + view { +
+
+ + + {#if !compact}{themeLabel}{/if} + +
+ {themeLabel} +
+ + +
+
+
+ +
+ + + {#if !compact}{colorLabel}{/if} + +
+ {colorLabel} +
+ {#each colors as item} + + {/each} +
+
+
+ +
+ + + + {#if !compact}{languageLabel}{/if} + +
+ {languageLabel} + {#each languages as item} + + {/each} +
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PublicPageShell.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PublicPageShell.wrn new file mode 100644 index 00000000..e98f9c02 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/PublicPageShell.wrn @@ -0,0 +1,53 @@ +component PublicPageShell { + props { + maxWidth = "full" + fullWidth = true + headerOffset = "none" + background = "default" + overflow = "clip" + minHeight = "screen" + size = "default" + color = "primary" + variant = "default" + class = "" + } + + view { +
+ + + {#if fullWidth} +
+ +
+ {:else} +
+ +
+ {/if} + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Radio.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Radio.wrn new file mode 100644 index 00000000..1da0c2a8 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Radio.wrn @@ -0,0 +1,56 @@ +component Radio { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Radio" + hiddenLabel = false + placeholder = "" + variant = "normal" + icon = "" + iconPosition = "start" + value = "on" + options = [] + checked = false + orientation = "vertical" + card = false + rightAligned = false + list = false + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { checked: sourceEvent.currentTarget.checked, value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
{#if options.length || cornerHint}{label}{#if cornerHint}{cornerHint}{/if}{/if}
+ {#if options.length} +
+ {#each options as option} + + {/each} +
+ {:else} + + {/if} + {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/RangeSlider.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/RangeSlider.wrn new file mode 100644 index 00000000..f501e7bb --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/RangeSlider.wrn @@ -0,0 +1,68 @@ +component RangeSlider { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Range" + hiddenLabel = false + placeholder = "" + variant = "normal" + icon = "" + iconPosition = "start" + value = 50 + min = 0 + max = 100 + step = 1 + showValue = true + showBounds = true + showSteps = false + marks = [] + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + state currentValue = value + functions { + function percent() { if (Number(max) === Number(min)) { return 0 } return (Number(currentValue) - Number(min)) / (Number(max) - Number(min)) * 100 } + function setValue(nextValue, sourceEvent, commit, detail, root, slider, input, output, progressValue) { if (readonly || disabled) { return } currentValue = Number(nextValue); root = sourceEvent.currentTarget.closest(".wire-next--range-slider"); if (root) { slider = root.querySelector("[role=slider]"); input = root.querySelector("input[name='" + name + "']"); output = root.querySelector("output"); progressValue = (currentValue - Number(min)) / (Number(max) - Number(min)) * 100; if (slider) { slider.setAttribute("aria-valuenow", String(currentValue)); slider.style.setProperty("--wire-range-progress", progressValue + "%") } if (input) { input.value = String(currentValue) } if (output) { output.textContent = String(currentValue) } } detail = { value: currentValue, min: min, max: max, step: step, name: name, sourceEvent: sourceEvent }; $emit("input", detail); if (commit) { $emit("change", detail) } } + function valueFromPointer(sourceEvent, rect, ratio) { rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); return Number(min) + ratio * (Number(max) - Number(min)) } + function beginSlide(sourceEvent, rect, ratio, rawValue) { if (readonly || disabled) { return } sourceEvent.currentTarget.setPointerCapture(sourceEvent.pointerId); rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function moveSlide(sourceEvent, rect, ratio, rawValue) { if (!sourceEvent.currentTarget.hasPointerCapture(sourceEvent.pointerId)) { return } rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function endSlide(sourceEvent, rect, ratio, rawValue) { rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); if (sourceEvent.currentTarget.hasPointerCapture(sourceEvent.pointerId)) { sourceEvent.currentTarget.releasePointerCapture(sourceEvent.pointerId) } $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function selectMark(sourceEvent, root, slider, input, output, nextValue, progressValue, detail) { if (readonly || disabled) { return } root = sourceEvent.currentTarget.closest(".wire-next--range-slider"); slider = root.querySelector(".wire-next__custom-slider"); input = root.querySelector(".wire-next__range-value"); output = root.querySelector("output"); nextValue = Number(sourceEvent.currentTarget.dataset.value); currentValue = nextValue; progressValue = (nextValue - Number(min)) / (Number(max) - Number(min)) * 100; slider.setAttribute("aria-valuenow", String(nextValue)); slider.style.setProperty("--wire-range-progress", progressValue + "%"); input.setAttribute("value", String(nextValue)); output.replaceChildren(String(nextValue)); detail = { value: nextValue, min: min, max: max, step: step, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function handleKey(sourceEvent) { if (sourceEvent.key === "ArrowRight") { sourceEvent.preventDefault(); currentValue = Math.min(Number(max), Number(currentValue) + Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "ArrowLeft") { sourceEvent.preventDefault(); currentValue = Math.max(Number(min), Number(currentValue) - Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "Home") { sourceEvent.preventDefault(); currentValue = Number(min); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "End") { sourceEvent.preventDefault(); currentValue = Number(max); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } } + function emitFocus(nameEvent, sourceEvent) { $emit(nameEvent, { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function decreaseValue(sourceEvent) { currentValue = Math.max(Number(min), Number(currentValue) - Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function increaseValue(sourceEvent) { currentValue = Math.min(Number(max), Number(currentValue) + Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if icon}{/if} + +
+ +
+ + {#if marks.length}{#each marks as mark}{/each}{/if} +
+ {#if showBounds}
{min}Step {step}{max}
{/if} +
+ {#if showValue}{currentValue}{/if} + +
+ {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Rating.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Rating.wrn new file mode 100644 index 00000000..a92de2af --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Rating.wrn @@ -0,0 +1,21 @@ +component Rating { + props { + @event input = function + @event change = function + size = "default" + color = "primary" + title = "Rating" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Scrollspy.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Scrollspy.wrn new file mode 100644 index 00000000..305d2d72 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Scrollspy.wrn @@ -0,0 +1,18 @@ +component Scrollspy { + props { + @event change = function + size = "default" + color = "primary" + label = "Scrollspy" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/SearchBox.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/SearchBox.wrn new file mode 100644 index 00000000..bcb7243a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/SearchBox.wrn @@ -0,0 +1,80 @@ +component SearchBox { + props { + size = "default" + color = "primary" + label = "Search Box" + name = "" + value = "" + placeholder = "" + type = "search" + min = "" + max = "" + step = "" + disabled = false + required = false + class = "" + } + + state query = value + + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Section.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Section.wrn new file mode 100644 index 00000000..c0e65c22 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Section.wrn @@ -0,0 +1,60 @@ +component Section { + props { + id = "" + size = "default" + color = "primary" + variant = "default" + spacing = "lg" + maxWidth = "xl" + fullWidth = false + borderTop = false + borderBottom = false + class = "" + } + + view { +
+ {#if fullWidth} + + {:else} + + + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/SectionHeader.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/SectionHeader.wrn new file mode 100644 index 00000000..a70c54fb --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/SectionHeader.wrn @@ -0,0 +1,113 @@ +component SectionHeader { + props { + id = "" + eyebrow = "" + title = "" + description = "" + align = "left" + size = "default" + color = "primary" + headingLevel = 2 + maxWidth = "3xl" + class = "" + } + + view { +
+
+
+ + + {#if eyebrow} +

+ {eyebrow} +

+ {/if} +
+ + {#if headingLevel === 1} +

+ {title} +

+ {:else if headingLevel === 3} +

+ {title} +

+ {:else} +

+ {title} +

+ {/if} + + {#if description} +

+ {description} +

+ {/if} + + +
+ +
+ +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Select.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Select.wrn new file mode 100644 index 00000000..23c13a94 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Select.wrn @@ -0,0 +1,61 @@ +component Select { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event open = function + @event close = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Select" + hiddenLabel = false + value = "" + values = [] + options = [] + placeholder = "Select an option" + variant = "normal" + icon = "" + iconPosition = "start" + helperText = "" + cornerHint = "" + error = "" + inline = false + multiple = false + readonly = false + disabled = false + required = false + class = "" + } + functions { + function selected(option) { + if (multiple) return values.includes(option.value) + return option.value === value + } + function emitField(nameEvent, sourceEvent) { + sourceEvent.stopPropagation() + $emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) + } + function handleFocus(sourceEvent) { emitField("focus", sourceEvent); $emit("open", { name: name, sourceEvent: sourceEvent }) } + function handleBlur(sourceEvent) { emitField("blur", sourceEvent); $emit("close", { name: name, sourceEvent: sourceEvent }) } + function handleInvalid(sourceEvent) { $emit("invalid", { name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if icon}{/if} + + {#if variant === "floating"}{label}{/if} +
+ {#if helperText}{helperText}{/if} + {error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Sidebar.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Sidebar.wrn new file mode 100644 index 00000000..7e64904a --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Sidebar.wrn @@ -0,0 +1,79 @@ +component Sidebar { + props { + @event toggle = function + @event open = function + @event close = function + @event select = function + size = "default" + color = "primary" + label = "Sidebar" + items = [] + active = "" + orientation = "horizontal" + mobileLabel = "Open navigation" + class = "" + } + + state mobileOpen = false + + functions { + function toggleSidebar() { + mobileOpen = !mobileOpen + $emit("toggle", { open: mobileOpen }) + $emit(mobileOpen ? "open" : "close", { source: "mobile" }) + } + + function closeSidebar() { + mobileOpen = false + $emit("close", { source: "mobile" }) + } + + function selectItem(item, level) { + mobileOpen = false + $emit("select", { item: item, value: item.value || "", level: level }) + } + } + + view { +
+ + + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/SplitHero.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/SplitHero.wrn new file mode 100644 index 00000000..cd523eb1 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/SplitHero.wrn @@ -0,0 +1,98 @@ +component SplitHero { + props { + eyebrow = "" + title = "A better digital experience" + highlight = "" + description = "" + primaryLabel = "" + primaryHref = "" + primaryIcon = "" + secondaryLabel = "" + secondaryHref = "" + secondaryIcon = "" + visualPosition = "right" + reverse = false + ratio = "balanced" + size = "default" + color = "primary" + variant = "default" + trustItems = [] + class = "" + } + + view { +
+
+
+ {#if eyebrow} +
+ + {eyebrow} +
+ {/if} + +

+ {title} + {#if highlight} + {highlight} + {/if} +

+ + {#if description} +

{description}

+ {/if} + + + + + + {#if trustItems.length > 0} +
+ {#each trustItems as item} + + + {item.label || item.title || item} + + {/each} +
+ {/if} + + + +
+ +
+ + +
+
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/StatsBar.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/StatsBar.wrn new file mode 100644 index 00000000..46cb04e9 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/StatsBar.wrn @@ -0,0 +1,40 @@ +component StatsBar { + props { + items = [] + columns = 4 + compact = true + dividers = true + icons = true + size = "default" + color = "primary" + variant = "raised" + maxWidth = "xl" + class = "" + } + + view { +
+
+ +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Stepper.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Stepper.wrn new file mode 100644 index 00000000..725ab1c2 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Stepper.wrn @@ -0,0 +1,21 @@ +component Stepper { + props { + @event change = function + @event previous = function + @event next = function + @event complete = function + size = "default" + color = "primary" + label = "Stepper" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/StrongPassword.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/StrongPassword.wrn new file mode 100644 index 00000000..d8f3137d --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/StrongPassword.wrn @@ -0,0 +1,215 @@ +component StrongPassword { + props { + size = "default" + color = "primary" + label = "Password" + name = "password" + value = "" + placeholder = "Create a strong password" + autocomplete = "new-password" + minLength = 8 + specialCharactersSet = "!@#$%^&*()_+-=[]{}|;:,.<>?" + requireLowercase = true + requireUppercase = true + requireNumber = true + requireSpecialCharacter = true + showRequirements = true + presentation = "inline" + hintText = "Use a unique password you do not use elsewhere." + emptyLabel = "Enter a password" + weakLabel = "Weak" + fairLabel = "Fair" + goodLabel = "Good" + strongLabel = "Strong" + disabled = false + readonly = false + required = false + invalid = false + validationMessage = "" + class = "" + @event input = function + @event change = function + @event strength = function + } + + state password = value + state detailsOpen = false + + functions { + function hasMinimumLength() { + return password.length >= Number(minLength) + } + + function hasLowercase() { + return password !== password.toUpperCase() + } + + function hasUppercase() { + return password !== password.toLowerCase() + } + + function hasNumber() { + return containsCharacterAt("0123456789", 0) + } + + function hasSpecialCharacter() { + return containsCharacterAt(specialCharactersSet, 0) + } + + function containsCharacterAt(characters, index) { + if (index >= characters.length) { + return false + } + if (password.includes(characters[index])) { + return true + } + return containsCharacterAt(characters, index + 1) + } + + function score() { + return (hasMinimumLength() ? 1 : 0) + (requireLowercase && hasLowercase() ? 1 : 0) + (requireUppercase && hasUppercase() ? 1 : 0) + (requireNumber && hasNumber() ? 1 : 0) + (requireSpecialCharacter && hasSpecialCharacter() ? 1 : 0) + } + + function maximumScore() { + return 1 + (requireLowercase ? 1 : 0) + (requireUppercase ? 1 : 0) + (requireNumber ? 1 : 0) + (requireSpecialCharacter ? 1 : 0) + } + + function strengthPercent() { + return Math.round(score() / maximumScore() * 100) + } + + function strengthLevel() { + if (!password) { + return "empty" + } + if (strengthPercent() <= 25) { + return "weak" + } + if (strengthPercent() <= 50) { + return "fair" + } + if (strengthPercent() < 100) { + return "good" + } + return "strong" + } + + function strengthLabel() { + if (strengthLevel() === "weak") { + return weakLabel + } + if (strengthLevel() === "fair") { + return fairLabel + } + if (strengthLevel() === "good") { + return goodLabel + } + if (strengthLevel() === "strong") { + return strongLabel + } + return emptyLabel + } + + } + + view { +
+ +
+ + + {#if presentation === "popover"} +
+ +
+
+ Password strength + {password ? strengthLabel() : emptyLabel} +
+
+ +
+ {#if showRequirements} +
    +
  • + At least {minLength} characters +
  • + {#if requireLowercase}
  • One lowercase letter
  • {/if} + {#if requireUppercase}
  • One uppercase letter
  • {/if} + {#if requireNumber}
  • One number
  • {/if} + {#if requireSpecialCharacter}
  • One special character: {specialCharactersSet}
  • {/if} +
+ {/if} + {#if hintText}{hintText}{/if} +
+
+ {/if} +
+ + {#if presentation !== "popover"} +
+
+ Password strength + {password ? strengthLabel() : emptyLabel} +
+
+ +
+ {#if showRequirements} +
    +
  • At least {minLength} characters
  • + {#if requireLowercase}
  • One lowercase letter
  • {/if} + {#if requireUppercase}
  • One uppercase letter
  • {/if} + {#if requireNumber}
  • One number
  • {/if} + {#if requireSpecialCharacter}
  • One special character: {specialCharactersSet}
  • {/if} +
+ {/if} + {#if hintText}{hintText}{/if} +
+ {/if} + + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/StyledIcon.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/StyledIcon.wrn new file mode 100644 index 00000000..a394af25 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/StyledIcon.wrn @@ -0,0 +1,19 @@ +component StyledIcon { + props { + size = "default" + color = "primary" + title = "Styled Icon" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Switch.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Switch.wrn new file mode 100644 index 00000000..478a92fe --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Switch.wrn @@ -0,0 +1,39 @@ +component Switch { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Switch" + hiddenLabel = false + placeholder = "" + variant = "normal" + icon = "" + iconPosition = "start" + value = "on" + checked = false + helperText = "" + cornerHint = "" + error = "" + inline = false + readonly = false + disabled = false + required = false + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { checked: sourceEvent.currentTarget.checked, value: value, name: name, sourceEvent: sourceEvent }) } + function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } + } + view { +
+
{#if cornerHint}{label}{cornerHint}{/if}
+ + {#if helperText}{helperText}{/if}{error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Tabs.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Tabs.wrn new file mode 100644 index 00000000..e8d747c4 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Tabs.wrn @@ -0,0 +1,90 @@ +component Tabs { + props { + size = "default" + color = "primary" + label = "Tabs" + items = [] + active = "" + orientation = "horizontal" + class = "" + } + + state activeValue = active || (items[0] ? (items[0].value || items[0].id || "0") : "") + + view { +
+
+ {#each items as item, index} + + {/each} +
+ +
+ {#each items as item, index} +
+ {#if item.title && item.title !== item.label} +

{item.title}

+ {/if} + {#if item.description} +

{item.description}

+ {/if} + {#if item.content} +
{item.content}
+ {/if} +
+ {/each} + + +
+
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/TextLink.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/TextLink.wrn new file mode 100644 index 00000000..a490e020 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/TextLink.wrn @@ -0,0 +1,87 @@ +component TextLink { + props { + @event click = function + @event focus = function + @event blur = function + label = "Learn more" + href = "#" + target = "" + rel = "" + external = false + icon = "" + iconPosition = "start" + showArrow = true + underline = false + size = "default" + color = "primary" + variant = "default" + disabled = false + class = "" + } + + view { + + {#if disabled} + + {#if icon && iconPosition === "start"} + + {/if} + {label} + + {:else} + + {#if icon && iconPosition === "start"} + + {/if} + + {label} + + {#if icon && iconPosition === "end"} + + {/if} + + {#if external} + + {:else if showArrow} + + {/if} + + {/if} + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Textarea.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Textarea.wrn new file mode 100644 index 00000000..98cfc33f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Textarea.wrn @@ -0,0 +1,53 @@ +component Textarea { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Textarea" + hiddenLabel = false + placeholder = "" + value = "" + variant = "normal" + icon = "" + iconPosition = "start" + helperText = "" + cornerHint = "" + error = "" + inline = false + rows = 5 + resize = "vertical" + readonly = false + disabled = false + required = false + minlength = "" + maxlength = "" + class = "" + } + functions { + function emitField(nameEvent, sourceEvent) { + sourceEvent.stopPropagation() + $emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) + } + function handleInvalid(sourceEvent) { + $emit("invalid", { value: sourceEvent.currentTarget.value, name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) + } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if icon}{/if} + + {#if variant === "floating"}{label}{/if} +
+ {#if helperText}{helperText}{/if} + {error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/TimePicker.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/TimePicker.wrn new file mode 100644 index 00000000..64398d44 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/TimePicker.wrn @@ -0,0 +1,63 @@ +component TimePicker { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + @event open = function + @event close = function + @event invalid = function + size = "default" + color = "primary" + id = "" + name = "" + label = "Time" + hiddenLabel = false + value = "" + placeholder = "" + variant = "normal" + icon = "icon-[lucide--clock-3]" + iconPosition = "end" + helperText = "" + cornerHint = "" + error = "" + inline = false + min = "" + max = "" + step = "" + format = "24" + minuteStep = 5 + hours = ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"] + minutes = ["00", "05", "10", "15", "20", "25", "30", "35", "40", "45", "50", "55"] + readonly = false + disabled = false + required = false + class = "" + } + state currentValue = value + state selectedHour = value ? value.split(":")[0] : "00" + state selectedMinute = value ? value.split(":")[1] : "00" + state expanded = false + functions { + function commit(part, nextValue, sourceEvent, next, detail) { if (part === "hour") { selectedHour = String(nextValue).padStart(2, "0") } if (part === "minute") { selectedMinute = String(nextValue).padStart(2, "0") } next = selectedHour + ":" + selectedMinute; if ((min && next < min) || (max && next > max)) { return } currentValue = next; detail = { value: currentValue, hour: selectedHour, minute: selectedMinute, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function selectTimePart(sourceEvent, root, input, parts, hourValue, minuteValue, next, trigger, detail) { root = sourceEvent.currentTarget.closest(".wire-next--time-picker"); input = root.querySelector(".wire-next__time-value"); parts = String(input.value || value || "00:00").split(":"); hourValue = sourceEvent.currentTarget.dataset.part === "hour" ? sourceEvent.currentTarget.dataset.value : parts[0]; minuteValue = sourceEvent.currentTarget.dataset.part === "minute" ? sourceEvent.currentTarget.dataset.value : parts[1]; next = hourValue + ":" + minuteValue; if ((min && next < min) || (max && next > max)) { return } currentValue = next; input.setAttribute("value", next); trigger = root.querySelector(".wire-next__time-trigger span"); if (trigger) { trigger.replaceChildren(next) } sourceEvent.currentTarget.setAttribute("aria-pressed", "true"); detail = { value: next, hour: hourValue, minute: minuteValue, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) } + function openPicker(sourceEvent) { expanded = true; $emit("open", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function closePicker(sourceEvent) { expanded = false; $emit("close", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleFocus(sourceEvent) { $emit("focus", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleBlur(sourceEvent) { $emit("blur", { value: currentValue, name: name, sourceEvent: sourceEvent }) } + function handleInvalid(sourceEvent) { $emit("invalid", { name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } + } + view { +
+
{#if cornerHint}{cornerHint}{/if}
+
+ {#if icon}{/if} + + +
+ + {#if helperText}{helperText}{/if} + {error} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Timeline.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Timeline.wrn new file mode 100644 index 00000000..3d3d35dd --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Timeline.wrn @@ -0,0 +1,83 @@ +component Timeline { + props { + size = "default" + color = "primary" + title = "Timeline" + description = "" + items = [] + variant = "default" + class = "" + } + + view { +
+ {#if title || description} +
+ {#if title} +

{title}

+ {/if} + {#if description} +

{description}

+ {/if} +
+ {/if} + +
    + {#each items as item, index} +
  1. + + + + +
    +
    +
    +

    {item.title || item.label}

    + {#if item.subtitle} +

    {item.subtitle}

    + {/if} +
    + {#if item.date || item.meta} + + {/if} +
    + + {#if item.description} +

    {item.description}

    + {/if} + + {#if item.href} + + {item.actionLabel || "View details"} + + + {/if} +
    +
  2. + {:empty} +
  3. No timeline items available.
  4. + {/each} +
+ + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Toast.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Toast.wrn new file mode 100644 index 00000000..bda42b49 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Toast.wrn @@ -0,0 +1,21 @@ +component Toast { + props { + @event dismiss = function + @event action = function + size = "default" + color = "primary" + title = "Toast" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ToastNotifications.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ToastNotifications.wrn new file mode 100644 index 00000000..d49d5547 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ToastNotifications.wrn @@ -0,0 +1,23 @@ +component ToastNotifications { + props { + @event add = function + @event dismiss = function + @event clear = function + @event action = function + size = "default" + color = "primary" + title = "Toast Notifications" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ToggleCount.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ToggleCount.wrn new file mode 100644 index 00000000..0a858af9 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ToggleCount.wrn @@ -0,0 +1,237 @@ +component ToggleCount { + props { + size = "default" + color = "primary" + variant = "segmented" + class = "" + + name = "billing-cycle" + value = "monthly" + firstValue = "monthly" + firstLabel = "Monthly" + secondValue = "annual" + secondLabel = "Annual" + ariaLabel = "Billing frequency" + + items = [] + currency = "$" + suffix = "" + firstValueKey = "monthly" + secondValueKey = "annual" + emptyValue = "—" + + align = "end" + fullWidth = true + disabled = false + animate = true + animationDuration = 450 + animationSteps = 18 + + @event change = function + @event toggle = function + } + + state selectedValue = value + + functions { + function isFirstSelected() { + return selectedValue === firstValue + } + + function isSecondSelected() { + return selectedValue === secondValue + } + + function displayValue(item) { + if (isSecondSelected()) { + return item[secondValueKey] !== undefined + ? item[secondValueKey] + : emptyValue + } + + return item[firstValueKey] !== undefined + ? item[firstValueKey] + : emptyValue + } + + function dispatchToggleEvent(sourceEvent, previousValue, root, customEvent) { + root = sourceEvent.currentTarget.closest("[data-wrn-toggle-count]") + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("change", true, false, { + component: "ToggleCount", + name: name, + value: selectedValue, + previousValue: previousValue, + firstValue: firstValue, + secondValue: secondValue + }) + root.dispatchEvent(customEvent) + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent("toggle", true, false, { + component: "ToggleCount", + name: name, + value: selectedValue, + previousValue: previousValue, + firstValue: firstValue, + secondValue: secondValue + }) + root.dispatchEvent(customEvent) + } + + function selectValue(sourceEvent, nextValue, previousValue) { + if (disabled || selectedValue === nextValue) { + return + } + + previousValue = selectedValue + selectedValue = nextValue + + if ( + animate && + !window.matchMedia("(prefers-reduced-motion: reduce)").matches + ) { + animateDisplayedValues(sourceEvent, previousValue) + } + + dispatchToggleEvent(sourceEvent, previousValue) + } + + function animateDisplayedValues(sourceEvent, previousValue, root, nodes) { + root = sourceEvent.currentTarget.closest("[data-wrn-toggle-count]") + + if (!root) { + return + } + + nodes = root.querySelectorAll("[data-toggle-count-value]") + animateValueAt(nodes, 0, previousValue) + } + + function animateValueAt(nodes, index, previousValue, node, fromValue, toValue) { + if (index >= nodes.length) { + return + } + + node = nodes[index] + fromValue = Number( + previousValue === secondValue + ? node.getAttribute("data-second-value") + : node.getAttribute("data-first-value") + ) + toValue = Number( + selectedValue === secondValue + ? node.getAttribute("data-second-value") + : node.getAttribute("data-first-value") + ) + + if (!Number.isNaN(fromValue) && !Number.isNaN(toValue)) { + animateValueFrame(node, fromValue, toValue, 0) + } + + animateValueAt(nodes, index + 1, previousValue) + } + + function animateValueFrame(node, fromValue, toValue, frame, totalFrames, nextValue) { + totalFrames = Math.max(1, Number(animationSteps) || 1) + + if (frame >= totalFrames) { + node.replaceChildren(String(toValue)) + return + } + + nextValue = Math.round( + fromValue + + (toValue - fromValue) * (frame / totalFrames) + ) + node.replaceChildren(String(nextValue)) + + setTimeout( + animateValueFrame, + Math.max(1, Number(animationDuration) / totalFrames), + node, + fromValue, + toValue, + frame + 1 + ) + } + + function toggleValue(sourceEvent) { + selectValue( + sourceEvent, + isFirstSelected() ? secondValue : firstValue + ) + } + } + + view { +
+ + +
+ {#if variant === "switch"} + {firstLabel} + + {secondLabel} + {:else} +
+ + +
+ {/if} +
+ + {#if items.length > 0} +
+ {#each items as item} +
+ {item.label || item.name} + + {#if currency}{currency}{/if} + {displayValue(item)} + {#if suffix}{suffix}{/if} + + {#if item.description}{item.description}{/if} +
+ {/each} +
+ {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/TogglePassword.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/TogglePassword.wrn new file mode 100644 index 00000000..43eb9cc6 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/TogglePassword.wrn @@ -0,0 +1,153 @@ +component TogglePassword { + props { + size = "default" + color = "primary" + label = "Password" + name = "password" + value = "" + placeholder = "Enter your password" + autocomplete = "current-password" + minlength = "" + maxlength = "" + pattern = "(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}" + fields = [] + visible = false + toggleable = true + toggleMode = "button" + checkboxLabel = "Show password" + showLabel = "Show password" + hideLabel = "Hide password" + disabled = false + readonly = false + required = false + invalid = false + helpText = "" + validationMessage = "" + class = "" + @event input = function + @event change = function + @event toggle = function + } + + state revealed = visible + + functions { + function toggleVisibility() { + if (disabled || readonly || !toggleable) { + return + } + revealed = !revealed + } + + function fieldId(field, index) { + return field.id || field.name || name + "-" + index + } + + function fieldName(field, index) { + return field.name || name + "-" + index + } + } + + view { +
+ {#if fields.length} +
+ {#each fields as field, index} +
+ +
+ + {#if toggleable && toggleMode === "button"} + + {/if} +
+
+ {/each} +
+ {:else} + +
+ + {#if toggleable && toggleMode === "button"} + + {/if} +
+ {/if} + {#if toggleable && toggleMode === "checkbox"} + + {/if} + {#if helpText && !validationMessage}{helpText}{/if} + {validationMessage} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/TreeView.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/TreeView.wrn new file mode 100644 index 00000000..d04a730b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/TreeView.wrn @@ -0,0 +1,23 @@ +component TreeView { + props { + @event select = function + @event toggle = function + @event expand = function + @event collapse = function + size = "default" + color = "primary" + title = "Tree View" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Typography.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Typography.wrn new file mode 100644 index 00000000..d7d36173 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/Typography.wrn @@ -0,0 +1,75 @@ +component Typography { + props { + size = "default" + color = "primary" + columns = 2 + gap = "md" + maxWidth = "xl" + class = "" + } + + view { +
+ +
+ } + + style { + .wire-typography :where(h1, h2, h3, h4) { + color: var(--wire-color-text); + font-weight: 700; + letter-spacing: -0.02em; + line-height: 1.2; + break-after: avoid; + } + + .wire-typography :where(h1) { font-size: clamp(2rem, 4vw, 3.5rem); margin: 0 0 1.5rem; } + .wire-typography :where(h2) { font-size: clamp(1.5rem, 3vw, 2.25rem); margin: 2.5rem 0 1rem; } + .wire-typography :where(h3) { font-size: 1.35rem; margin: 2rem 0 0.75rem; } + .wire-typography :where(p, ul, ol, blockquote, pre, table) { margin: 1rem 0; } + .wire-typography :where(p, li) { color: var(--wire-color-text-muted); line-height: 1.8; } + .wire-typography :where(a) { color: var(--wire-color-primary); font-weight: 600; text-underline-offset: 0.2em; } + .wire-typography :where(a:hover) { color: var(--wire-color-primary-hover); text-decoration: underline; } + .wire-typography :where(ul, ol) { padding-left: 1.4rem; } + .wire-typography :where(ul) { list-style: disc; } + .wire-typography :where(ol) { list-style: decimal; } + .wire-typography :where(blockquote) { + border-left: 4px solid var(--wire-color-primary); + background: var(--wire-color-primary-soft); + border-radius: 0 0.75rem 0.75rem 0; + padding: 1rem 1.25rem; + color: var(--wire-color-text); + } + .wire-typography :where(code) { + border-radius: 0.35rem; + background: var(--wire-color-surface-soft); + padding: 0.15rem 0.35rem; + font-size: 0.9em; + } + .wire-typography :where(pre) { + overflow-x: auto; + border: 1px solid var(--wire-color-border); + border-radius: 1rem; + background: var(--wire-color-surface-raised); + padding: 1rem; + } + .wire-typography :where(img) { border-radius: 1rem; } + .wire-typography :where(hr) { border-color: var(--wire-color-border); margin: 2rem 0; } + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/WysiwygEditor.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/WysiwygEditor.wrn new file mode 100644 index 00000000..dfb91935 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/WysiwygEditor.wrn @@ -0,0 +1,23 @@ +component WysiwygEditor { + props { + @event input = function + @event change = function + @event focus = function + @event blur = function + size = "default" + color = "primary" + title = "Wysiwyg Editor" + description = "" + items = [] + variant = "default" + class = "" + } + view { +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + {#if items}
{#each items as item}{item.label}{/each}
{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/alert.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/alert.wrn new file mode 100644 index 00000000..ba2e904b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/alert.wrn @@ -0,0 +1,142 @@ +component Alert { + props { + size = "default" + color = "info" + variant = "soft" + class = "" + radius = "md" + shadow = "sm" + + title = "Alert" + description = "" + items = [] + actions = [] + + showIcon = false + icon = "" + dismissible = false + dismissLabel = "Dismiss alert" + role = "alert" + live = "polite" + + linkLabel = "" + linkHref = "" + actionLabel = "" + actionHref = "" + compact = false + + @event dismiss = function + @event action = function + } + + state visible = true + + functions { + function dispatchAlertEvent(sourceEvent, eventName, action, root, customEvent) { + root = sourceEvent.currentTarget.closest("[data-wrn-alert]") + + if (!root) { + return + } + + customEvent = document.createEvent("CustomEvent") + customEvent.initCustomEvent(eventName, true, false, { + component: "Alert", + title: title, + color: color, + variant: variant, + action: action + }) + root.dispatchEvent(customEvent) + } + + function dismissAlert(sourceEvent) { + visible = false + dispatchAlertEvent(sourceEvent, "dismiss", null) + } + + function selectAction(sourceEvent, action) { + dispatchAlertEvent(sourceEvent, "action", action) + } + } + + view { +
+ {#if showIcon} + + {/if} + +
+ {#if title}{title}{/if} + {#if description}

{description}

{/if} + + {#if items.length > 0} +
    + {#each items as item}
  • {item.label || item}
  • {/each} +
+ {/if} + + {#if actions.length > 0 || actionLabel || linkLabel} +
+ {#each actions as item} + {item.label} + {/each} + {#if actionLabel} + {actionLabel} + {/if} + {#if linkLabel} + {linkLabel} + {/if} +
+ {/if} +
+ + {#if dismissible} + + {/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/avatar.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/avatar.wrn new file mode 100644 index 00000000..1c90e813 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/avatar.wrn @@ -0,0 +1,87 @@ +component Avatar { + props { + @event load = function + @event error = function + @event click = function + src = "" + alt = "" + initials = "" + size = "md" + color = "primary" + variant = "solid" + shape = "circle" + + status = "" + statusLabel = "" + statusPosition = "bottom" + + badge = "" + badgeIcon = "" + badgeLabel = "" + + tooltip = "" + name = "" + description = "" + loading = "lazy" + class = "" + } + + view { + + + + {#if src} + {alt || name} + {:else if initials} + + {:else} + + {/if} + + + {#if status} + + {/if} + + {#if badgeIcon} + + + + {:else if badge} + + {badge} + + {/if} + + {#if tooltip} + {tooltip} + {/if} + + + {#if description} + + {name || alt || initials} + {description} + + {/if} + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/button.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/button.wrn new file mode 100644 index 00000000..34bf88b4 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/button.wrn @@ -0,0 +1,164 @@ +component Button { + props { + @event click = function + @event focus = function + @event blur = function + label = "Button" + loadingLabel = "Loading…" + description = "" + as = "" + href = "" + target = "" + rel = "" + type = "button" + variant = "default" + color = "primary" + size = "default" + disabled = false + loading = false + pill = false + fullWidth = false + icon = "" + iconPosition = "start" + ariaLabel = "" + ariaPressed = "" + ariaExpanded = "" + ariaControls = "" + title = "" + autofocus = false + controlClass = "" + class = "" + } + + view { + + {#if as === "a" || (as === "" && href)} + + {#if loading} + + {/if} + {#if icon && !loading && iconPosition === "start"} + + {/if} + + + {loading ? loadingLabel : label} + + {#if description && !loading} + + {description} + + {/if} + + {#if icon && !loading && iconPosition === "end"} + + {/if} + {#if (size === "icon" || size === "icon-xs" || size === "icon-sm" || size === "icon-lg") && (ariaLabel || label)} + + {/if} + + {:else} + + {/if} + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/carousel.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/carousel.wrn new file mode 100644 index 00000000..4efdb206 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/carousel.wrn @@ -0,0 +1,461 @@ +// Interactive, hydration-safe content carousel. +component Carousel { + props { + @event initialize = function + @event change = function + @event previous = function + @event next = function + @event play = function + @event pause = function + @event reachStart = function + @event reachEnd = function + @event dragStart = function + @event dragEnd = function + size = "default" + color = "primary" + title = "" + description = "" + items = [] + activeIndex = 0 + slidesPerView = 1 + gap = "0.75rem" + showPagination = false + isAutoPlay = false + autoplayInterval = 4000 + isInfiniteLoop = false + isRTL = false + isCentered = false + isDraggable = false + isAutoHeight = false + isSnap = false + showCounter = false + thumbnails = "none" + ariaLabel = "Content carousel" + variant = "default" + class = "" + } + + state currentIndex = activeIndex + state playing = false + state dragOrigin = null + state dragOffset = 0 + state autoplayTimer = null + state carouselRoot = null + + functions { + function slideCount() { + return items.length + } + + function maximumIndex(count, visible) { + count = slideCount() + visible = Math.max(1, Number(slidesPerView) || 1) + if (isCentered || isSnap) { + return Math.max(0, count - 1) + } + return Math.max(0, count - visible) + } + + function normalizedIndex(index, maximum) { + maximum = maximumIndex() + if (slideCount() === 0) { + return 0 + } + if (isInfiniteLoop) { + if (index < 0) { + return maximum + } + if (index > maximum) { + return 0 + } + } + return Math.max(0, Math.min(index, maximum)) + } + + function rememberRoot(sourceEvent, root) { + if (!sourceEvent || !sourceEvent.currentTarget) { + return + } + root = sourceEvent.currentTarget.closest(".wire-next--carousel") + if (root) { + carouselRoot = root + } + } + + function syncNavigation(sourceEvent, index, root, viewport, slides, slide, thumbnails, thumbnail, rail) { + rememberRoot(sourceEvent) + root = carouselRoot + if (!root) { + return + } + if (isSnap) { + viewport = root.querySelector(".wire-next__carousel-viewport") + slides = root.querySelectorAll(".wire-next__carousel-slide") + slide = slides[index] + if (viewport && slide) { + viewport.scrollTo({ + left: slide.offsetLeft - (viewport.clientWidth - slide.clientWidth) / 2, + behavior: "smooth" + }) + } + } + thumbnails = root.querySelectorAll(".wire-next__carousel-thumbnails button") + if (thumbnails[index]) { + thumbnail = thumbnails[index] + rail = thumbnail.parentElement + rail.scrollTo({ + left: thumbnail.offsetLeft - (rail.clientWidth - thumbnail.clientWidth) / 2, + top: thumbnail.offsetTop - (rail.clientHeight - thumbnail.clientHeight) / 2, + behavior: "smooth" + }) + } + } + + function handleSnapScroll(sourceEvent, slides, viewport, viewportCenter, closestIndex, closestDistance, slide, slideCenter, distance, previousIndex) { + if (!isSnap) { + return + } + rememberRoot(sourceEvent) + viewport = sourceEvent.currentTarget + slides = viewport.querySelectorAll(".wire-next__carousel-slide") + viewportCenter = viewport.scrollLeft + viewport.clientWidth / 2 + closestIndex = currentIndex + closestDistance = 1000000000 + slides.forEach(function (candidate, index) { + slideCenter = candidate.offsetLeft + candidate.clientWidth / 2 + distance = Math.abs(slideCenter - viewportCenter) + if (distance < closestDistance) { + closestDistance = distance + closestIndex = index + } + }) + closestIndex = normalizedIndex(closestIndex) + if (closestIndex !== currentIndex) { + previousIndex = currentIndex + currentIndex = closestIndex + $emit("change", { + index: currentIndex, + previousIndex: previousIndex, + item: items[currentIndex], + reason: "snap" + }) + slides = carouselRoot.querySelectorAll(".wire-next__carousel-thumbnails button") + slide = slides[currentIndex] + if (slide) { + viewport = slide.parentElement + viewport.scrollTo({ + left: slide.offsetLeft - (viewport.clientWidth - slide.clientWidth) / 2, + top: slide.offsetTop - (viewport.clientHeight - slide.clientHeight) / 2, + behavior: "smooth" + }) + } + } + } + + function selectSlide(index, reason, sourceEvent, previousIndex) { + if (slideCount() === 0) { + return + } + previousIndex = currentIndex + currentIndex = normalizedIndex(Number(index)) + syncNavigation(sourceEvent, currentIndex) + if (previousIndex === currentIndex && reason !== "initialize") { + return + } + $emit("change", { + index: currentIndex, + previousIndex: previousIndex, + item: items[currentIndex], + reason: reason || "select" + }) + if (currentIndex === 0) { + $emit("reachStart", { index: currentIndex }) + } + if (currentIndex === maximumIndex()) { + $emit("reachEnd", { index: currentIndex }) + } + } + + function previousSlide(sourceEvent, previousIndex) { + previousIndex = currentIndex + selectSlide(currentIndex - 1, "previous", sourceEvent) + $emit("previous", { + index: currentIndex, + previousIndex: previousIndex, + item: items[currentIndex] + }) + } + + function nextSlide(sourceEvent, previousIndex) { + previousIndex = currentIndex + selectSlide(currentIndex + 1, "next", sourceEvent) + $emit("next", { + index: currentIndex, + previousIndex: previousIndex, + item: items[currentIndex] + }) + } + + function handleKeydown(sourceEvent) { + if (sourceEvent.key === "ArrowLeft") { + sourceEvent.preventDefault() + if (isRTL) { + nextSlide(sourceEvent) + } else { + previousSlide(sourceEvent) + } + } + if (sourceEvent.key === "ArrowRight") { + sourceEvent.preventDefault() + if (isRTL) { + previousSlide(sourceEvent) + } else { + nextSlide(sourceEvent) + } + } + if (sourceEvent.key === "Home") { + sourceEvent.preventDefault() + selectSlide(0, "keyboard", sourceEvent) + } + if (sourceEvent.key === "End") { + sourceEvent.preventDefault() + selectSlide(maximumIndex(), "keyboard", sourceEvent) + } + } + + function beginDrag(sourceEvent) { + if (!isDraggable || isSnap) { + return + } + sourceEvent.preventDefault() + dragOrigin = sourceEvent.clientX + dragOffset = 0 + sourceEvent.currentTarget.setPointerCapture(sourceEvent.pointerId) + $emit("dragStart", { index: currentIndex, x: dragOrigin }) + } + + function moveDrag(sourceEvent) { + if (!isDraggable || isSnap || dragOrigin === null) { + return + } + sourceEvent.preventDefault() + dragOffset = sourceEvent.clientX - dragOrigin + } + + function cancelDrag() { + dragOrigin = null + dragOffset = 0 + } + + function endDrag(sourceEvent, distance) { + if (!isDraggable || isSnap || dragOrigin === null) { + return + } + sourceEvent.preventDefault() + distance = dragOffset || sourceEvent.clientX - dragOrigin + dragOrigin = null + dragOffset = 0 + if (Math.abs(distance) > 20) { + if ((distance < 0 && !isRTL) || (distance > 0 && isRTL)) { + nextSlide(sourceEvent) + } else { + previousSlide(sourceEvent) + } + } + $emit("dragEnd", { + index: currentIndex, + distance: distance + }) + } + + function advanceAutoplay() { + if (currentIndex >= maximumIndex()) { + selectSlide(0, "autoplay") + } else { + selectSlide(currentIndex + 1, "autoplay") + } + } + + function startAutoplay() { + if (!isAutoPlay || playing || slideCount() < 2) { + return + } + playing = true + autoplayTimer = setInterval(advanceAutoplay, Math.max(1000, Number(autoplayInterval))) + $emit("play", { index: currentIndex, interval: autoplayInterval }) + } + + function pauseAutoplay() { + if (autoplayTimer) { + clearInterval(autoplayTimer) + } + autoplayTimer = null + if (playing) { + $emit("pause", { index: currentIndex }) + } + playing = false + } + + } + + lifecycle { + mount { + $emit("initialize", { index: currentIndex, count: slideCount() }) + startAutoplay() + } + unmount { + if (autoplayTimer) { + clearInterval(autoplayTimer) + } + } + } + + view { + + } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/component-catalog.json b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/component-catalog.json new file mode 100644 index 00000000..299cb70b --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/component-catalog.json @@ -0,0 +1,549 @@ +{ + "sourceDocuments": ["Screenshot-directed WRNexus UI catalog reset"], + "components": [ + { + "name": "Accordion", + "category": "base", + "purpose": "Theme-aware, responsive accordion component." + }, + { + "name": "AdvancedDatePicker", + "category": "integrations", + "purpose": "Theme-aware, responsive advanced date picker component." + }, + { + "name": "AdvancedRangeSlider", + "category": "integrations", + "purpose": "Theme-aware, responsive advanced range slider component." + }, + { + "name": "AdvancedSelect", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive advanced select component.", + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"] + }, + { + "name": "Alert", + "category": "base", + "purpose": "Theme-aware, responsive alert component." + }, + { + "name": "AnnouncementBar", + "category": "blocks", + "purpose": "Accessible public announcement, emergency, maintenance, or status bar." + }, + { + "name": "AuthForm", + "category": "forms", + "purpose": "Reusable authentication form for sign-in, registration, recovery, reset, and MFA." + }, + { + "name": "AuthSplitLayout", + "category": "layout", + "purpose": "Responsive 50/50 authentication layout with content and form regions." + }, + { + "name": "Avatar", + "category": "base", + "purpose": "Theme-aware, responsive avatar component." + }, + { + "name": "AvatarGroup", + "category": "base", + "purpose": "Theme-aware, responsive avatar group component." + }, + { + "name": "BackToTop", + "category": "navigation", + "purpose": "Accessible scroll-to-top control with visibility threshold." + }, + { + "name": "Badge", + "category": "base", + "purpose": "Theme-aware, responsive badge component." + }, + { + "name": "Blockquote", + "category": "base", + "purpose": "Theme-aware, responsive blockquote component." + }, + { + "name": "Breadcrumb", + "category": "navigation", + "purpose": "Theme-aware, responsive breadcrumb component." + }, + { + "name": "Button", + "category": "base", + "purpose": "Theme-aware, responsive button component." + }, + { + "name": "ButtonGroup", + "category": "base", + "purpose": "Theme-aware, responsive button group component." + }, + { + "name": "Card", + "category": "base", + "purpose": "Theme-aware, responsive card component." + }, + { + "name": "Carousel", + "category": "base", + "purpose": "Theme-aware, responsive carousel component." + }, + { + "name": "Chart", + "category": "integrations", + "purpose": "Theme-aware, responsive chart component." + }, + { + "name": "ChatBubble", + "category": "base", + "purpose": "Theme-aware, responsive chat bubble component." + }, + { + "name": "Checkbox", + "category": "forms", + "purpose": "Theme-aware, responsive checkbox component." + }, + { + "name": "Clipboard", + "category": "integrations", + "purpose": "Theme-aware, responsive clipboard component." + }, + { + "name": "Collapse", + "category": "base", + "purpose": "Theme-aware, responsive collapse component." + }, + { + "name": "ColorPicker", + "category": "forms", + "purpose": "Theme-aware, responsive color picker component." + }, + { + "name": "Columns", + "category": "layout", + "purpose": "Theme-aware, responsive columns component." + }, + { + "name": "ComboBox", + "category": "advanced-forms", + "purpose": "Editable autocomplete combobox with local and remote suggestions.", + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"] + }, + { + "name": "Confetti", + "category": "integrations", + "purpose": "Theme-aware, responsive confetti component." + }, + { + "name": "Container", + "category": "layout", + "purpose": "Theme-aware, responsive container component." + }, + { + "name": "ContextMenu", + "category": "overlays", + "purpose": "Theme-aware, responsive context menu component." + }, + { + "name": "CopyMarkup", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive copy markup component." + }, + { + "name": "CTASection", + "category": "blocks", + "purpose": "Reusable closing call-to-action section with primary and secondary actions." + }, + { + "name": "CustomScrollbar", + "category": "layout", + "purpose": "Theme-aware, responsive custom scrollbar component." + }, + { + "name": "DataMap", + "category": "integrations", + "purpose": "Theme-aware, responsive data map component." + }, + { + "name": "DataTable", + "category": "integrations", + "purpose": "Theme-aware, responsive data table component." + }, + { + "name": "DatePicker", + "category": "base", + "purpose": "Theme-aware, responsive date picker component." + }, + { + "name": "DeviceFrame", + "category": "base", + "purpose": "Theme-aware, responsive device frame component." + }, + { + "name": "Divider", + "category": "layout", + "purpose": "Theme-aware, responsive divider component." + }, + { + "name": "DragAndDrop", + "category": "integrations", + "purpose": "Theme-aware, responsive drag and drop component." + }, + { + "name": "Drawer", + "category": "overlays", + "purpose": "Theme-aware, responsive drawer component." + }, + { + "name": "Dropdown", + "category": "overlays", + "purpose": "Theme-aware, responsive dropdown component." + }, + { + "name": "FeatureCard", + "category": "blocks", + "purpose": "Reusable linked feature or service card with icon, badge, description, and action." + }, + { + "name": "FeatureGrid", + "category": "layout", + "purpose": "Responsive equal-height grid for feature and service cards." + }, + { + "name": "FeatureIconCard", + "category": "blocks", + "purpose": "Feature card with a prominent themed icon treatment." + }, + { + "name": "FileInput", + "category": "forms", + "purpose": "Theme-aware, responsive file input component." + }, + { + "name": "FileUpload", + "category": "integrations", + "purpose": "Theme-aware, responsive file upload component." + }, + { + "name": "FileUploadProgress", + "category": "base", + "purpose": "Theme-aware, responsive file upload progress component." + }, + { + "name": "Footer", + "category": "navigation", + "purpose": "Responsive application footer with structured links and pre/post content slots." + }, + { + "name": "Grid", + "category": "layout", + "purpose": "Theme-aware, responsive grid component." + }, + { + "name": "Hero", + "category": "blocks", + "purpose": "Reusable public-page hero with actions, trust items, badges, and visual slots." + }, + { + "name": "HeroActions", + "category": "base", + "purpose": "Responsive action group for hero and call-to-action sections." + }, + { + "name": "Image", + "category": "layout", + "purpose": "Theme-aware, responsive image component." + }, + { + "name": "Input", + "category": "forms", + "purpose": "Theme-aware, responsive input component." + }, + { + "name": "InputGroup", + "category": "forms", + "purpose": "Theme-aware, responsive input group component." + }, + { + "name": "InputNumber", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive input number component." + }, + { + "name": "Kbd", + "category": "layout", + "purpose": "Theme-aware, responsive kbd component." + }, + { + "name": "LayoutSplitter", + "category": "layout", + "purpose": "Theme-aware, responsive layout splitter component." + }, + { + "name": "LegendIndicator", + "category": "base", + "purpose": "Theme-aware, responsive legend indicator component." + }, + { + "name": "Link", + "category": "layout", + "purpose": "Theme-aware, responsive link component." + }, + { + "name": "List", + "category": "base", + "purpose": "Theme-aware, responsive list component." + }, + { + "name": "ListGroup", + "category": "base", + "purpose": "Theme-aware, responsive list group component." + }, + { + "name": "Map", + "category": "integrations", + "purpose": "Theme-aware, responsive map component." + }, + { + "name": "MarketingSectionHeader", + "category": "blocks", + "purpose": "Marketing section heading with an optional linked action." + }, + { + "name": "Marquee", + "category": "base", + "purpose": "Theme-aware, responsive marquee component." + }, + { + "name": "MegaMenu", + "category": "navigation", + "purpose": "Theme-aware, responsive mega menu component." + }, + { + "name": "MetricCard", + "category": "blocks", + "purpose": "Single statistic or operational metric with icon, trend, and optional action." + }, + { + "name": "MetricGrid", + "category": "layout", + "purpose": "Responsive collection of metric cards." + }, + { + "name": "Modal", + "category": "overlays", + "purpose": "Theme-aware, responsive modal component." + }, + { + "name": "Nav", + "category": "navigation", + "purpose": "Theme-aware, responsive nav component." + }, + { + "name": "Navbar", + "category": "navigation", + "purpose": "Theme-aware, responsive navbar component." + }, + { + "name": "PageHeader", + "category": "blocks", + "purpose": "Public and application page header with breadcrumbs, metadata, and actions." + }, + { + "name": "Pagination", + "category": "navigation", + "purpose": "Theme-aware, responsive pagination component." + }, + { + "name": "PinInput", + "category": "advanced-forms", + "purpose": "Secure multi-cell PIN and verification-code input with regex and paste support.", + "events": ["input", "change", "complete", "paste", "clear", "error"] + }, + { + "name": "Popover", + "category": "overlays", + "purpose": "Theme-aware, responsive popover component." + }, + { + "name": "PortalDashboard", + "category": "blocks", + "purpose": "Responsive portal dashboard with metrics, actions, tasks, and updates." + }, + { + "name": "PreferenceSwitcher", + "category": "navigation", + "purpose": "Accessible theme, accent color, and language preference controls." + }, + { + "name": "Progress", + "category": "base", + "purpose": "Theme-aware, responsive progress component." + }, + { + "name": "PublicPageShell", + "category": "layout", + "purpose": "Consistent structural wrapper for public-facing pages." + }, + { + "name": "Radio", + "category": "forms", + "purpose": "Theme-aware, responsive radio component." + }, + { + "name": "RangeSlider", + "category": "forms", + "purpose": "Theme-aware, responsive range slider component." + }, + { + "name": "Rating", + "category": "base", + "purpose": "Theme-aware, responsive rating component." + }, + { + "name": "Scrollspy", + "category": "navigation", + "purpose": "Theme-aware, responsive scrollspy component." + }, + { + "name": "SearchBox", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive search box component." + }, + { + "name": "Section", + "category": "layout", + "purpose": "Theme-aware page section with consistent spacing, width, background, and border controls." + }, + { + "name": "SectionHeader", + "category": "layout", + "purpose": "Reusable accessible section heading with eyebrow, title, description, icon, and actions." + }, + { + "name": "Select", + "category": "forms", + "purpose": "Theme-aware, responsive select component." + }, + { + "name": "Sidebar", + "category": "navigation", + "purpose": "Theme-aware, responsive sidebar component." + }, + { + "name": "Skeleton", + "category": "base", + "purpose": "Theme-aware, responsive skeleton component." + }, + { + "name": "Spinner", + "category": "base", + "purpose": "Theme-aware, responsive spinner component." + }, + { + "name": "SplitHero", + "category": "blocks", + "purpose": "Two-column hero with configurable content and visual placement." + }, + { + "name": "StatsBar", + "category": "blocks", + "purpose": "Compact responsive statistics strip." + }, + { + "name": "Stepper", + "category": "navigation", + "purpose": "Theme-aware, responsive stepper component." + }, + { + "name": "StrongPassword", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive strong password component." + }, + { + "name": "StyledIcon", + "category": "base", + "purpose": "Theme-aware, responsive styled icon component." + }, + { + "name": "Switch", + "category": "forms", + "purpose": "Theme-aware, responsive switch component." + }, + { + "name": "Table", + "category": "tables", + "purpose": "Theme-aware, responsive table component." + }, + { + "name": "Tabs", + "category": "navigation", + "purpose": "Theme-aware, responsive tabs component." + }, + { + "name": "Textarea", + "category": "forms", + "purpose": "Theme-aware, responsive textarea component." + }, + { + "name": "TextLink", + "category": "layout", + "purpose": "Styled inline action link with icons, arrows, external state, and disabled handling." + }, + { + "name": "Timeline", + "category": "base", + "purpose": "Theme-aware, responsive timeline component." + }, + { + "name": "TimePicker", + "category": "forms", + "purpose": "Theme-aware, responsive time picker component." + }, + { + "name": "Toast", + "category": "base", + "purpose": "Theme-aware, responsive toast component." + }, + { + "name": "ToastNotifications", + "category": "integrations", + "purpose": "Theme-aware, responsive toast notifications component." + }, + { + "name": "ToggleCount", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive toggle count component." + }, + { + "name": "TogglePassword", + "category": "advanced-forms", + "purpose": "Accessible password field with optional show and hide controls.", + "events": ["input", "change", "toggle"] + }, + { + "name": "Tooltip", + "category": "overlays", + "purpose": "Theme-aware, responsive tooltip component." + }, + { + "name": "TreeView", + "category": "base", + "purpose": "Theme-aware, responsive tree view component." + }, + { + "name": "Typography", + "category": "layout", + "purpose": "Theme-aware, responsive typography component." + }, + { + "name": "WysiwygEditor", + "category": "integrations", + "purpose": "Theme-aware, responsive wysiwyg editor component." + } + ] +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/component-reference.json b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/component-reference.json new file mode 100644 index 00000000..8a319957 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/component-reference.json @@ -0,0 +1,9773 @@ +{ + "generatedFrom": "packages/ui/components/*.wrn", + "count": 108, + "components": [ + { + "name": "Accordion", + "mount": "Accordion", + "category": "base", + "purpose": "Theme-aware, responsive accordion component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"accordion\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "defaultOpen", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "alwaysOpen", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "indicator", + "type": "string", + "required": false, + "default": "\"plus\"" + }, + { + "name": "indicatorPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "showIndicator", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "bordered", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "separated", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "flush", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "contentItalic", + "type": "boolean", + "required": false, + "default": "false" + } + ], + "slots": [], + "events": ["change", "open", "close"], + "source": "components/Accordion.wrn" + }, + { + "name": "AdvancedDatePicker", + "mount": "AdvancedDatePicker", + "category": "integrations", + "purpose": "Theme-aware, responsive advanced date picker component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Advanced Date Picker\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change", "open", "close", "clear"], + "source": "components/AdvancedDatePicker.wrn" + }, + { + "name": "AdvancedRangeSlider", + "mount": "AdvancedRangeSlider", + "category": "integrations", + "purpose": "Theme-aware, responsive advanced range slider component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Advanced Range Slider\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change", "start", "end"], + "source": "components/AdvancedRangeSlider.wrn" + }, + { + "name": "AdvancedSelect", + "mount": "AdvancedSelect", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive advanced select component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Advanced Select\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "values", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "groups", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Select an option\"" + }, + { + "name": "placeholderIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "searchPlaceholder", + "type": "string", + "required": false, + "default": "\"Search options…\"" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "searchable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "defaultOpen", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "clearable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "allowEmpty", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "tags", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "loading", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "loadingLabel", + "type": "string", + "required": false, + "default": "\"Loading options…\"" + }, + { + "name": "emptyLabel", + "type": "string", + "required": false, + "default": "\"No options found\"" + }, + { + "name": "selectedOptionsLabel", + "type": "string", + "required": false, + "default": "\"Selected options\"" + }, + { + "name": "clearLabel", + "type": "string", + "required": false, + "default": "\"Clear selection\"" + }, + { + "name": "createLabel", + "type": "string", + "required": false, + "default": "\"Create\"" + }, + { + "name": "loadMoreLabel", + "type": "string", + "required": false, + "default": "\"Load more\"" + }, + { + "name": "searchMode", + "type": "string", + "required": false, + "default": "\"contains\"" + }, + { + "name": "searchFields", + "type": "string", + "required": false, + "default": "\"label,description\"" + }, + { + "name": "minSearchLength", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "searchResultLimit", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "maxSelections", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "showCounter", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "counterTemplate", + "type": "string", + "required": false, + "default": "\"{selected} selected\"" + }, + { + "name": "optionTemplate", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "selectedTemplate", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "closeOnSelect", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "scrollToSelected", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fixed", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "remote", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "remoteUrl", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "remoteQueryParam", + "type": "string", + "required": false, + "default": "\"q\"" + }, + { + "name": "remoteDebounce", + "type": "number", + "required": false, + "default": "250" + }, + { + "name": "remoteAutoLoad", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "infinite", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "hasMore", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "page", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"], + "source": "components/AdvancedSelect.wrn" + }, + { + "name": "Alert", + "mount": "Alert", + "category": "base", + "purpose": "Theme-aware, responsive alert component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"info\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"soft\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "radius", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "shadow", + "type": "string", + "required": false, + "default": "\"sm\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Alert\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "actions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "showIcon", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "dismissible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dismissLabel", + "type": "string", + "required": false, + "default": "\"Dismiss alert\"" + }, + { + "name": "role", + "type": "string", + "required": false, + "default": "\"alert\"" + }, + { + "name": "live", + "type": "string", + "required": false, + "default": "\"polite\"" + }, + { + "name": "linkLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "linkHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "false" + } + ], + "slots": [], + "events": ["dismiss", "action"], + "source": "components/alert.wrn" + }, + { + "name": "AnnouncementBar", + "mount": "AnnouncementBar", + "category": "blocks", + "purpose": "Accessible public announcement, emergency, maintenance, or status bar.", + "props": [ + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badgeIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "message", + "type": "string", + "required": false, + "default": "\"Announcement\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--megaphone]\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "dismissible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dismissLabel", + "type": "string", + "required": false, + "default": "\"Dismiss announcement\"" + }, + { + "name": "sticky", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"soft\"" + }, + { + "name": "role", + "type": "string", + "required": false, + "default": "\"status\"" + }, + { + "name": "live", + "type": "string", + "required": false, + "default": "\"polite\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/AnnouncementBar.wrn" + }, + { + "name": "AuthForm", + "mount": "AuthForm", + "category": "forms", + "purpose": "Reusable authentication form for sign-in, registration, recovery, reset, and MFA.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "mode", + "type": "string", + "required": false, + "default": "\"sign-in\"" + }, + { + "name": "action", + "type": "string", + "required": false, + "default": "\"/api/auth/login\"" + }, + { + "name": "method", + "type": "string", + "required": false, + "default": "\"post\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Sign in\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "returnTo", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "schema", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "showRemember", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showName", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "submitLabel", + "type": "string", + "required": false, + "default": "\"Continue\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["submit", "change", "input", "focus", "blur"], + "source": "components/AuthForm.wrn" + }, + { + "name": "AuthSplitLayout", + "mount": "AuthSplitLayout", + "category": "layout", + "purpose": "Responsive 50/50 authentication layout with content and form regions.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"Secure identity\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Welcome back\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "brand", + "type": "string", + "required": false, + "default": "\"Police Management System\"" + }, + { + "name": "features", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["aside-extra", "form"], + "events": [], + "source": "components/AuthSplitLayout.wrn" + }, + { + "name": "Avatar", + "mount": "Avatar", + "category": "base", + "purpose": "Theme-aware, responsive avatar component.", + "props": [ + { + "name": "src", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "alt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "initials", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "shape", + "type": "string", + "required": false, + "default": "\"circle\"" + }, + { + "name": "status", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "statusLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "statusPosition", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badgeIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badgeLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "tooltip", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "loading", + "type": "string", + "required": false, + "default": "\"lazy\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["load", "error", "click"], + "source": "components/avatar.wrn" + }, + { + "name": "AvatarGroup", + "mount": "AvatarGroup", + "category": "base", + "purpose": "Theme-aware, responsive avatar group component.", + "props": [ + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "shape", + "type": "string", + "required": false, + "default": "\"circle\"" + }, + { + "name": "layout", + "type": "string", + "required": false, + "default": "\"stack\"" + }, + { + "name": "maxVisible", + "type": "number", + "required": false, + "default": "4" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "borderColor", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "showTooltips", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "overflowLabel", + "type": "string", + "required": false, + "default": "\"Show remaining members\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["overflow"], + "source": "components/AvatarGroup.wrn" + }, + { + "name": "BackToTop", + "mount": "BackToTop", + "category": "navigation", + "purpose": "Accessible scroll-to-top control with visibility threshold.", + "props": [ + { + "name": "threshold", + "type": "number", + "required": false, + "default": "500" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Back to top\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Scroll back to top\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--arrow-up]\"" + }, + { + "name": "position", + "type": "string", + "required": false, + "default": "\"right\"" + }, + { + "name": "offset", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "behavior", + "type": "string", + "required": false, + "default": "\"smooth\"" + }, + { + "name": "showProgress", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/BackToTop.wrn" + }, + { + "name": "Badge", + "mount": "Badge", + "category": "base", + "purpose": "Theme-aware, responsive badge component.", + "props": [ + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Badge\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "shape", + "type": "string", + "required": false, + "default": "\"pill\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "dot", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dotOnly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dotLabel", + "type": "string", + "required": false, + "default": "\"Status\"" + }, + { + "name": "animated", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "avatarSrc", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "avatarAlt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "dismissible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "dismissLabel", + "type": "string", + "required": false, + "default": "\"Remove badge\"" + }, + { + "name": "truncate", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"12rem\"" + }, + { + "name": "anchorLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "anchorIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"inline\"" + }, + { + "name": "anchorLabelText", + "type": "string", + "required": false, + "default": "\"Badge anchor\"" + } + ], + "slots": [], + "events": ["dismiss"], + "source": "components/Badge.wrn" + }, + { + "name": "Blockquote", + "mount": "Blockquote", + "category": "base", + "purpose": "Theme-aware, responsive blockquote component.", + "props": [ + { + "name": "quote", + "type": "string", + "required": false, + "default": "\"I just wanted to say that I'm very happy with my purchase so far. The documentation is outstanding - clear and detailed.\"" + }, + { + "name": "citation", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "citationTitle", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "citationUrl", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "avatarSrc", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "avatarAlt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "quoteMark", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "italic", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Blockquote.wrn" + }, + { + "name": "Breadcrumb", + "mount": "Breadcrumb", + "category": "navigation", + "purpose": "Theme-aware, responsive breadcrumb component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Breadcrumb\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["navigate", "click"], + "source": "components/Breadcrumb.wrn" + }, + { + "name": "Button", + "mount": "Button", + "category": "base", + "purpose": "Theme-aware, responsive button component.", + "props": [ + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Button\"" + }, + { + "name": "loadingLabel", + "type": "string", + "required": false, + "default": "\"Loading…\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "as", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "target", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "rel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"button\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "loading", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "pill", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "ariaPressed", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "ariaExpanded", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "ariaControls", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "autofocus", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "controlClass", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["click", "focus", "blur"], + "source": "components/button.wrn" + }, + { + "name": "ButtonGroup", + "mount": "ButtonGroup", + "category": "base", + "purpose": "Theme-aware, responsive button group component.", + "props": [ + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "responsive", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "attached", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "selectable", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "toolbar", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Button group\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["click", "select", "change"], + "source": "components/ButtonGroup.wrn" + }, + { + "name": "Card", + "mount": "Card", + "category": "base", + "purpose": "Theme-aware, responsive card component.", + "props": [ + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Card title\"" + }, + { + "name": "subtitle", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "header", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "footer", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "imageSrc", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "imageAlt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "imagePosition", + "type": "string", + "required": false, + "default": "\"top\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "headerActions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "navigation", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "activeNav", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "mobileNavigation", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "alertTitle", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "alertDescription", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "empty", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "emptyTitle", + "type": "string", + "required": false, + "default": "\"No data to show\"" + }, + { + "name": "emptyIcon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--inbox]\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "layout", + "type": "string", + "required": false, + "default": "\"vertical\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "hover", + "type": "string", + "required": false, + "default": "\"none\"" + }, + { + "name": "scrollable", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "maxHeight", + "type": "string", + "required": false, + "default": "\"18rem\"" + }, + { + "name": "dismissible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["click", "action", "navigate", "dismiss", "load", "error"], + "source": "components/Card.wrn" + }, + { + "name": "Carousel", + "mount": "Carousel", + "category": "base", + "purpose": "Theme-aware, responsive carousel component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "activeIndex", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "slidesPerView", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"0.75rem\"" + }, + { + "name": "showPagination", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isAutoPlay", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "autoplayInterval", + "type": "number", + "required": false, + "default": "4000" + }, + { + "name": "isInfiniteLoop", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isRTL", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isCentered", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isDraggable", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isAutoHeight", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "isSnap", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showCounter", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "thumbnails", + "type": "string", + "required": false, + "default": "\"none\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Content carousel\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [ + "initialize", + "change", + "previous", + "next", + "play", + "pause", + "reachStart", + "reachEnd", + "dragStart", + "dragEnd" + ], + "source": "components/carousel.wrn" + }, + { + "name": "Chart", + "mount": "Chart", + "category": "integrations", + "purpose": "Theme-aware, responsive chart component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Chart\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "dataPointClick", "legendToggle"], + "source": "components/Chart.wrn" + }, + { + "name": "ChatBubble", + "mount": "ChatBubble", + "category": "base", + "purpose": "Theme-aware, responsive chat bubble component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "oneSided", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showAvatars", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showMetadata", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Conversation\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["action", "messageClick", "avatarClick", "linkClick"], + "source": "components/ChatBubble.wrn" + }, + { + "name": "Checkbox", + "mount": "Checkbox", + "category": "forms", + "purpose": "Theme-aware, responsive checkbox component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Checkbox\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"on\"" + }, + { + "name": "values", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "checked", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "indeterminate", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"vertical\"" + }, + { + "name": "card", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "rightAligned", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "list", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change", "focus", "blur", "invalid"], + "source": "components/Checkbox.wrn" + }, + { + "name": "Clipboard", + "mount": "Clipboard", + "category": "integrations", + "purpose": "Theme-aware, responsive clipboard component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Clipboard\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["copy", "success", "error"], + "source": "components/Clipboard.wrn" + }, + { + "name": "Collapse", + "mount": "Collapse", + "category": "base", + "purpose": "Theme-aware, responsive collapse component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "mode", + "type": "string", + "required": false, + "default": "\"panel\"" + }, + { + "name": "initialOpenIndexes", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Collapsible content\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["toggle", "open", "close"], + "source": "components/Collapse.wrn" + }, + { + "name": "ColorPicker", + "mount": "ColorPicker", + "category": "forms", + "purpose": "Theme-aware, responsive color picker component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Color\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"#2563eb\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur"], + "source": "components/ColorPicker.wrn" + }, + { + "name": "Columns", + "mount": "Columns", + "category": "layout", + "purpose": "Theme-aware, responsive columns component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Columns.wrn" + }, + { + "name": "ComboBox", + "mount": "ComboBox", + "category": "advanced-forms", + "purpose": "Editable autocomplete combobox with local and remote suggestions.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"ComboBox\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "groups", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Search or select an option\"" + }, + { + "name": "searchPlaceholder", + "type": "string", + "required": false, + "default": "\"Start typing…\"" + }, + { + "name": "clearable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "allowCustomValue", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "loading", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "loadingLabel", + "type": "string", + "required": false, + "default": "\"Loading suggestions…\"" + }, + { + "name": "emptyLabel", + "type": "string", + "required": false, + "default": "\"No matching options\"" + }, + { + "name": "clearLabel", + "type": "string", + "required": false, + "default": "\"Clear value\"" + }, + { + "name": "toggleLabel", + "type": "string", + "required": false, + "default": "\"Toggle suggestions\"" + }, + { + "name": "searchMode", + "type": "string", + "required": false, + "default": "\"contains\"" + }, + { + "name": "searchFields", + "type": "string", + "required": false, + "default": "\"label,description\"" + }, + { + "name": "minSearchLength", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "searchResultLimit", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "optionTemplate", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "defaultOpen", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "closeOnSelect", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fixed", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"off\"" + }, + { + "name": "remote", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "remoteUrl", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "remoteQueryParam", + "type": "string", + "required": false, + "default": "\"q\"" + }, + { + "name": "remoteDebounce", + "type": "number", + "required": false, + "default": "250" + }, + { + "name": "remoteAutoLoad", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "infinite", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "hasMore", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "page", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "loadMoreLabel", + "type": "string", + "required": false, + "default": "\"Load more\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"], + "source": "components/Combobox.wrn" + }, + { + "name": "Confetti", + "mount": "Confetti", + "category": "integrations", + "purpose": "Theme-aware, responsive confetti component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Confetti\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["start", "complete"], + "source": "components/Confetti.wrn" + }, + { + "name": "Container", + "mount": "Container", + "category": "layout", + "purpose": "Theme-aware, responsive container component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Container.wrn" + }, + { + "name": "ContextMenu", + "mount": "ContextMenu", + "category": "overlays", + "purpose": "Theme-aware, responsive context menu component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Context Menu\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close", "select"], + "source": "components/ContextMenu.wrn" + }, + { + "name": "CopyMarkup", + "mount": "CopyMarkup", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive copy markup component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Copy Markup\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"text\"" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["copy", "success", "error"], + "source": "components/CopyMarkup.wrn" + }, + { + "name": "CTASection", + "mount": "CTASection", + "category": "blocks", + "purpose": "Reusable closing call-to-action section with primary and secondary actions.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Ready to get started?\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"center\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"solid\"" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"Get started\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"#\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "backgroundImage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default", "actions", "visual", "footer"], + "events": [], + "source": "components/CTASection.wrn" + }, + { + "name": "CustomScrollbar", + "mount": "CustomScrollbar", + "category": "layout", + "purpose": "Theme-aware, responsive custom scrollbar component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["scroll"], + "source": "components/CustomScrollbar.wrn" + }, + { + "name": "DataMap", + "mount": "DataMap", + "category": "integrations", + "purpose": "Theme-aware, responsive data map component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Data Map\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "change"], + "source": "components/DataMap.wrn" + }, + { + "name": "DataTable", + "mount": "DataTable", + "category": "integrations", + "purpose": "Theme-aware, responsive data table component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "caption", + "type": "string", + "required": false, + "default": "\"Data Table\"" + }, + { + "name": "columns", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "rows", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "striped", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["sort", "select", "change", "rowClick", "pageChange"], + "source": "components/DataTable.wrn" + }, + { + "name": "DatePicker", + "mount": "DatePicker", + "category": "base", + "purpose": "Theme-aware, responsive date picker component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Date Picker\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"date\"" + }, + { + "name": "locale", + "type": "string", + "required": false, + "default": "\"en-US\"" + }, + { + "name": "firstDayOfWeek", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "months", + "type": "string", + "required": false, + "default": "[{ label: \"Jan\", value: \"01\" }, { label: \"Feb\", value: \"02\" }, { label: \"Mar\", value: \"03\" }, { label: \"Apr\", value: \"04\" }, { label: \"May\", value: \"05\" }, { label: \"Jun\", value: \"06\" }, { label: \"Jul\", value: \"07\" }, { label: \"Aug\", value: \"08\" }, { label: \"Sep\", value: \"09\" }, { label: \"Oct\", value: \"10\" }, { label: \"Nov\", value: \"11\" }, { label: \"Dec\", value: \"12\" }]" + }, + { + "name": "days", + "type": "string", + "required": false, + "default": "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]" + }, + { + "name": "years", + "type": "string", + "required": false, + "default": "[2024, 2025, 2026, 2027, 2028, 2029, 2030]" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "open", "close", "focus", "blur", "invalid"], + "source": "components/DatePicker.wrn" + }, + { + "name": "DeviceFrame", + "mount": "DeviceFrame", + "category": "base", + "purpose": "Theme-aware, responsive device frame component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Device Frame\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "device", + "type": "string", + "required": false, + "default": "\"phone\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"portrait\"" + }, + { + "name": "src", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "srcdoc", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "frameTitle", + "type": "string", + "required": false, + "default": "\"Device preview\"" + }, + { + "name": "showToolbar", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "allow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["change", "rotate"], + "source": "components/DeviceFrame.wrn" + }, + { + "name": "Divider", + "mount": "Divider", + "category": "layout", + "purpose": "Theme-aware, responsive divider component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/Divider.wrn" + }, + { + "name": "DragAndDrop", + "mount": "DragAndDrop", + "category": "integrations", + "purpose": "Theme-aware, responsive drag and drop component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Drag And Drop\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["dragStart", "dragEnd", "dragEnter", "dragLeave", "drop", "change"], + "source": "components/DragAndDrop.wrn" + }, + { + "name": "Drawer", + "mount": "Drawer", + "category": "overlays", + "purpose": "Theme-aware, responsive drawer component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Drawer\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close"], + "source": "components/Drawer.wrn" + }, + { + "name": "Dropdown", + "mount": "Dropdown", + "category": "overlays", + "purpose": "Theme-aware, responsive dropdown component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Open menu\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"end\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["trigger", "header", "footer"], + "events": ["toggle", "open", "close", "select"], + "source": "components/Dropdown.wrn" + }, + { + "name": "FeatureCard", + "mount": "FeatureCard", + "category": "blocks", + "purpose": "Reusable linked feature or service card with icon, badge, description, and action.", + "props": [ + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Feature\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"Learn more\"" + }, + { + "name": "actionIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badgeColor", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "hover", + "type": "string", + "required": false, + "default": "\"lift\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["icon", "default", "footer"], + "events": [], + "source": "components/FeatureCard.wrn" + }, + { + "name": "FeatureGrid", + "mount": "FeatureGrid", + "category": "layout", + "purpose": "Responsive equal-height grid for feature and service cards.", + "props": [ + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "tabletColumns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "mobileColumns", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "minItemWidth", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "equalHeight", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"stretch\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"full\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/FeatureGrid.wrn" + }, + { + "name": "FeatureIconCard", + "mount": "FeatureIconCard", + "category": "blocks", + "purpose": "Feature card with a prominent themed icon treatment.", + "props": [ + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--sparkles]\"" + }, + { + "name": "iconSize", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "iconVariant", + "type": "string", + "required": false, + "default": "\"soft\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Feature\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"Explore\"" + }, + { + "name": "badge", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "hover", + "type": "string", + "required": false, + "default": "\"lift\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default", "footer"], + "events": [], + "source": "components/FeatureIconCard.wrn" + }, + { + "name": "FileInput", + "mount": "FileInput", + "category": "forms", + "purpose": "Theme-aware, responsive file input component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"File\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Choose a file\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--upload]\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "accept", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "select", "clear", "invalid"], + "source": "components/FileInput.wrn" + }, + { + "name": "FileUpload", + "mount": "FileUpload", + "category": "integrations", + "purpose": "Theme-aware, responsive file upload component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"File Upload\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "upload", "progress", "success", "error", "cancel", "remove"], + "source": "components/FileUpload.wrn" + }, + { + "name": "FileUploadProgress", + "mount": "FileUploadProgress", + "category": "base", + "purpose": "Theme-aware, responsive file upload progress component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Progress\"" + }, + { + "name": "value", + "type": "number", + "required": false, + "default": "50" + }, + { + "name": "max", + "type": "number", + "required": false, + "default": "100" + }, + { + "name": "showValue", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fileName", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "fileSize", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "uploadedSize", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "status", + "type": "string", + "required": false, + "default": "\"uploading\"" + }, + { + "name": "cancelLabel", + "type": "string", + "required": false, + "default": "\"Cancel upload\"" + }, + { + "name": "retryLabel", + "type": "string", + "required": false, + "default": "\"Retry upload\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["cancel", "retry", "complete"], + "source": "components/FileUploadProgress.wrn" + }, + { + "name": "Footer", + "mount": "Footer", + "category": "navigation", + "purpose": "Responsive application footer with structured links and pre/post content slots.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Footer navigation\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"compact\"" + }, + { + "name": "copyright", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["pre-footer", "copyright-left", "copyright-right", "post-footer"], + "events": ["select", "action"], + "source": "components/Footer.wrn" + }, + { + "name": "Grid", + "mount": "Grid", + "category": "layout", + "purpose": "Theme-aware, responsive grid component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Grid.wrn" + }, + { + "name": "Hero", + "mount": "Hero", + "category": "blocks", + "purpose": "Reusable public-page hero with actions, trust items, badges, and visual slots.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Build something remarkable\"" + }, + { + "name": "highlight", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "tertiaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "tertiaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "badges", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "trustItems", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["eyebrow", "actions", "trust", "default", "visual", "footer"], + "events": [], + "source": "components/Hero.wrn" + }, + { + "name": "HeroActions", + "mount": "HeroActions", + "category": "base", + "purpose": "Responsive action group for hero and call-to-action sections.", + "props": [ + { + "name": "actions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "stackOnMobile", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fullWidthMobile", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/HeroActions.wrn" + }, + { + "name": "Image", + "mount": "Image", + "category": "layout", + "purpose": "Theme-aware, responsive image component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "src", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "alt", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "width", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "height", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "loading", + "type": "string", + "required": false, + "default": "\"lazy\"" + }, + { + "name": "rounded", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Image.wrn" + }, + { + "name": "Input", + "mount": "Input", + "category": "forms", + "purpose": "Theme-aware, responsive input component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Input\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"text\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inputmode", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "minlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "maxlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "pattern", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "invalid", "keydown", "keyup"], + "source": "components/Input.wrn" + }, + { + "name": "InputGroup", + "mount": "InputGroup", + "category": "forms", + "purpose": "Theme-aware, responsive input group component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Input group\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"text\"" + }, + { + "name": "startText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "endText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "submit", "action"], + "source": "components/InputGroup.wrn" + }, + { + "name": "InputNumber", + "mount": "InputNumber", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive input number component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"quantity\"" + }, + { + "name": "value", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "precision", + "type": "string", + "required": false, + "default": "\"auto\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "prefix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "suffix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"off\"" + }, + { + "name": "inputMode", + "type": "string", + "required": false, + "default": "\"decimal\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "inputDisabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "buttonsDisabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "allowInput", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "keyboard", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "wheel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "clamp", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showButtons", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showValidationMessage", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "decrementLabel", + "type": "string", + "required": false, + "default": "\"Decrease value\"" + }, + { + "name": "incrementLabel", + "type": "string", + "required": false, + "default": "\"Increase value\"" + }, + { + "name": "controlsLabel", + "type": "string", + "required": false, + "default": "\"Quantity controls\"" + }, + { + "name": "requiredMessage", + "type": "string", + "required": false, + "default": "\"A value is required.\"" + }, + { + "name": "minMessage", + "type": "string", + "required": false, + "default": "\"Value is below the minimum.\"" + }, + { + "name": "maxMessage", + "type": "string", + "required": false, + "default": "\"Value is above the maximum.\"" + } + ], + "slots": [], + "events": ["input", "change", "increment", "decrement"], + "source": "components/InputNumber.wrn" + }, + { + "name": "Kbd", + "mount": "Kbd", + "category": "layout", + "purpose": "Theme-aware, responsive kbd component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"⌘ K\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Kbd.wrn" + }, + { + "name": "LayoutSplitter", + "mount": "LayoutSplitter", + "category": "layout", + "purpose": "Theme-aware, responsive layout splitter component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["resizeStart", "resize", "resizeEnd"], + "source": "components/LayoutSplitter.wrn" + }, + { + "name": "LegendIndicator", + "mount": "LegendIndicator", + "category": "base", + "purpose": "Theme-aware, responsive legend indicator component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Legend Indicator\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["toggle", "select"], + "source": "components/LegendIndicator.wrn" + }, + { + "name": "Link", + "mount": "Link", + "category": "layout", + "purpose": "Theme-aware, responsive link component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Link\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"#\"" + }, + { + "name": "target", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "rel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "external", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Link.wrn" + }, + { + "name": "List", + "mount": "List", + "category": "base", + "purpose": "Theme-aware, responsive list component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"List\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/List.wrn" + }, + { + "name": "ListGroup", + "mount": "ListGroup", + "category": "base", + "purpose": "Theme-aware, responsive list group component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"List Group\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "change"], + "source": "components/ListGroup.wrn" + }, + { + "name": "Map", + "mount": "Map", + "category": "integrations", + "purpose": "Theme-aware, responsive map component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Map\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Map.wrn" + }, + { + "name": "MarketingSectionHeader", + "mount": "MarketingSectionHeader", + "category": "blocks", + "purpose": "Marketing section heading with an optional linked action.", + "props": [ + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"split\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionExternal", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["icon", "actions", "default"], + "events": [], + "source": "components/MarketingSectionHeader.wrn" + }, + { + "name": "Marquee", + "mount": "Marquee", + "category": "base", + "purpose": "Theme-aware, responsive marquee component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Marquee\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Marquee.wrn" + }, + { + "name": "MegaMenu", + "mount": "MegaMenu", + "category": "navigation", + "purpose": "Theme-aware, responsive mega menu component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Mega Menu\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close", "select"], + "source": "components/MegaMenu.wrn" + }, + { + "name": "MetricCard", + "mount": "MetricCard", + "category": "blocks", + "purpose": "Single statistic or operational metric with icon, trend, and optional action.", + "props": [ + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Metric\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"0\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "prefix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "suffix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "trend", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "trendLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "trendDirection", + "type": "string", + "required": false, + "default": "\"neutral\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "actionLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/MetricCard.wrn" + }, + { + "name": "MetricGrid", + "mount": "MetricGrid", + "category": "layout", + "purpose": "Responsive collection of metric cards.", + "props": [ + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "4" + }, + { + "name": "tabletColumns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "mobileColumns", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "equalHeight", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "dividers", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/MetricGrid.wrn" + }, + { + "name": "Modal", + "mount": "Modal", + "category": "overlays", + "purpose": "Theme-aware, responsive modal component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Modal\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close", "cancel", "confirm"], + "source": "components/Modal.wrn" + }, + { + "name": "Nav", + "mount": "Nav", + "category": "navigation", + "purpose": "Theme-aware, responsive nav component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Nav\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "change"], + "source": "components/Nav.wrn" + }, + { + "name": "Navbar", + "mount": "Navbar", + "category": "navigation", + "purpose": "Theme-aware, responsive navbar component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Primary navigation\"" + }, + { + "name": "topbarLabel", + "type": "string", + "required": false, + "default": "\"Utility navigation\"" + }, + { + "name": "brand", + "type": "string", + "required": false, + "default": "{}" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "actions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "sticky", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "openOnHover", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"full\"" + }, + { + "name": "mobileLabel", + "type": "string", + "required": false, + "default": "\"Toggle navigation\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["topbar", "actions"], + "events": ["toggle", "open", "close", "select", "action"], + "source": "components/Navbar.wrn" + }, + { + "name": "PageHeader", + "mount": "PageHeader", + "category": "blocks", + "purpose": "Public and application page header with breadcrumbs, metadata, and actions.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "showBreadcrumbs", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "breadcrumbs", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["meta", "actions", "default"], + "events": [], + "source": "components/PageHeader.wrn" + }, + { + "name": "Pagination", + "mount": "Pagination", + "category": "navigation", + "purpose": "Theme-aware, responsive pagination component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Pagination\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["change", "previous", "next"], + "source": "components/Pagination.wrn" + }, + { + "name": "PinInput", + "mount": "PinInput", + "category": "advanced-forms", + "purpose": "Secure multi-cell PIN and verification-code input with regex and paste support.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Verification code\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"pin\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "length", + "type": "number", + "required": false, + "default": "4" + }, + { + "name": "pattern", + "type": "string", + "required": false, + "default": "\"[0-9]\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"text\"" + }, + { + "name": "inputMode", + "type": "string", + "required": false, + "default": "\"numeric\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"○\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"one-time-code\"" + }, + { + "name": "masked", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "autoFocus", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "autoSubmit", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "allowPaste", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "clearable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "clearLabel", + "type": "string", + "required": false, + "default": "\"Clear code\"" + }, + { + "name": "separator", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "groupSize", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "complete", "paste", "clear", "error"], + "source": "components/PinInput.wrn" + }, + { + "name": "Popover", + "mount": "Popover", + "category": "overlays", + "purpose": "Theme-aware, responsive popover component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Popover\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close"], + "source": "components/Popover.wrn" + }, + { + "name": "PortalDashboard", + "mount": "PortalDashboard", + "category": "blocks", + "purpose": "Responsive portal dashboard with metrics, actions, tasks, and updates.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"Overview\"" + }, + { + "name": "eyebrowKey", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Dashboard\"" + }, + { + "name": "titleKey", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "descriptionKey", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "userName", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "metrics", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "actions", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "updates", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "tasks", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["hero-action"], + "events": ["action", "navigate"], + "source": "components/PortalDashboard.wrn" + }, + { + "name": "PreferenceSwitcher", + "mount": "PreferenceSwitcher", + "category": "navigation", + "purpose": "Accessible theme, accent color, and language preference controls.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "themeLabel", + "type": "string", + "required": false, + "default": "\"Theme\"" + }, + { + "name": "colorLabel", + "type": "string", + "required": false, + "default": "\"Accent color\"" + }, + { + "name": "languageLabel", + "type": "string", + "required": false, + "default": "\"Language\"" + }, + { + "name": "languages", + "type": "string", + "required": false, + "default": "[" + }, + { + "name": "colors", + "type": "string", + "required": false, + "default": "[" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["theme", "color", "language"], + "source": "components/PreferenceSwitcher.wrn" + }, + { + "name": "Progress", + "mount": "Progress", + "category": "base", + "purpose": "Theme-aware, responsive progress component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Progress\"" + }, + { + "name": "value", + "type": "number", + "required": false, + "default": "50" + }, + { + "name": "max", + "type": "number", + "required": false, + "default": "100" + }, + { + "name": "showValue", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/progress.wrn" + }, + { + "name": "PublicPageShell", + "mount": "PublicPageShell", + "category": "layout", + "purpose": "Consistent structural wrapper for public-facing pages.", + "props": [ + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"full\"" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "headerOffset", + "type": "string", + "required": false, + "default": "\"none\"" + }, + { + "name": "background", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "overflow", + "type": "string", + "required": false, + "default": "\"clip\"" + }, + { + "name": "minHeight", + "type": "string", + "required": false, + "default": "\"screen\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["before", "default", "after"], + "events": [], + "source": "components/PublicPageShell.wrn" + }, + { + "name": "Radio", + "mount": "Radio", + "category": "forms", + "purpose": "Theme-aware, responsive radio component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Radio\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"on\"" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "checked", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"vertical\"" + }, + { + "name": "card", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "rightAligned", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "list", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "invalid"], + "source": "components/Radio.wrn" + }, + { + "name": "RangeSlider", + "mount": "RangeSlider", + "category": "forms", + "purpose": "Theme-aware, responsive range slider component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Range\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "value", + "type": "number", + "required": false, + "default": "50" + }, + { + "name": "min", + "type": "number", + "required": false, + "default": "0" + }, + { + "name": "max", + "type": "number", + "required": false, + "default": "100" + }, + { + "name": "step", + "type": "number", + "required": false, + "default": "1" + }, + { + "name": "showValue", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showBounds", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showSteps", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "marks", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur"], + "source": "components/RangeSlider.wrn" + }, + { + "name": "Rating", + "mount": "Rating", + "category": "base", + "purpose": "Theme-aware, responsive rating component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Rating\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change"], + "source": "components/Rating.wrn" + }, + { + "name": "Scrollspy", + "mount": "Scrollspy", + "category": "navigation", + "purpose": "Theme-aware, responsive scrollspy component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Scrollspy\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["change"], + "source": "components/Scrollspy.wrn" + }, + { + "name": "SearchBox", + "mount": "SearchBox", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive search box component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Search Box\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "\"search\"" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/SearchBox.wrn" + }, + { + "name": "Section", + "mount": "Section", + "category": "layout", + "purpose": "Theme-aware page section with consistent spacing, width, background, and border controls.", + "props": [ + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "spacing", + "type": "string", + "required": false, + "default": "\"lg\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "borderTop", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "borderBottom", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Section.wrn" + }, + { + "name": "SectionHeader", + "mount": "SectionHeader", + "category": "layout", + "purpose": "Reusable accessible section heading with eyebrow, title, description, icon, and actions.", + "props": [ + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"left\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "headingLevel", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"3xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["icon", "default", "actions"], + "events": [], + "source": "components/SectionHeader.wrn" + }, + { + "name": "Select", + "mount": "Select", + "category": "forms", + "purpose": "Theme-aware, responsive select component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Select\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "values", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "options", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Select an option\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "multiple", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "open", "close", "invalid"], + "source": "components/Select.wrn" + }, + { + "name": "Sidebar", + "mount": "Sidebar", + "category": "navigation", + "purpose": "Theme-aware, responsive sidebar component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Sidebar\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "mobileLabel", + "type": "string", + "required": false, + "default": "\"Open navigation\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["toggle", "open", "close", "select"], + "source": "components/Sidebar.wrn" + }, + { + "name": "Skeleton", + "mount": "Skeleton", + "category": "base", + "purpose": "Theme-aware, responsive skeleton component.", + "props": [ + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Loading\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "lines", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/skeleton.wrn" + }, + { + "name": "Spinner", + "mount": "Spinner", + "category": "base", + "purpose": "Theme-aware, responsive spinner component.", + "props": [ + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Loading\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "lines", + "type": "number", + "required": false, + "default": "3" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/spinner.wrn" + }, + { + "name": "SplitHero", + "mount": "SplitHero", + "category": "blocks", + "purpose": "Two-column hero with configurable content and visual placement.", + "props": [ + { + "name": "eyebrow", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"A better digital experience\"" + }, + { + "name": "highlight", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "primaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryLabel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryHref", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "secondaryIcon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "visualPosition", + "type": "string", + "required": false, + "default": "\"right\"" + }, + { + "name": "reverse", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "ratio", + "type": "string", + "required": false, + "default": "\"balanced\"" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "trustItems", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["actions", "trust", "default", "visual"], + "events": [], + "source": "components/SplitHero.wrn" + }, + { + "name": "StatsBar", + "mount": "StatsBar", + "category": "blocks", + "purpose": "Compact responsive statistics strip.", + "props": [ + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "4" + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "dividers", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "icons", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"raised\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": [], + "source": "components/StatsBar.wrn" + }, + { + "name": "Stepper", + "mount": "Stepper", + "category": "navigation", + "purpose": "Theme-aware, responsive stepper component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Stepper\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["change", "previous", "next", "complete"], + "source": "components/Stepper.wrn" + }, + { + "name": "StrongPassword", + "mount": "StrongPassword", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive strong password component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Password\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"password\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Create a strong password\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"new-password\"" + }, + { + "name": "minLength", + "type": "number", + "required": false, + "default": "8" + }, + { + "name": "specialCharactersSet", + "type": "string", + "required": false, + "default": "\"!@#$%^&*()_+-=[]{}|;:,.<>?\"" + }, + { + "name": "requireLowercase", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "requireUppercase", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "requireNumber", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "requireSpecialCharacter", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "showRequirements", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "presentation", + "type": "string", + "required": false, + "default": "\"inline\"" + }, + { + "name": "hintText", + "type": "string", + "required": false, + "default": "\"Use a unique password you do not use elsewhere.\"" + }, + { + "name": "emptyLabel", + "type": "string", + "required": false, + "default": "\"Enter a password\"" + }, + { + "name": "weakLabel", + "type": "string", + "required": false, + "default": "\"Weak\"" + }, + { + "name": "fairLabel", + "type": "string", + "required": false, + "default": "\"Fair\"" + }, + { + "name": "goodLabel", + "type": "string", + "required": false, + "default": "\"Good\"" + }, + { + "name": "strongLabel", + "type": "string", + "required": false, + "default": "\"Strong\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "strength"], + "source": "components/StrongPassword.wrn" + }, + { + "name": "StyledIcon", + "mount": "StyledIcon", + "category": "base", + "purpose": "Theme-aware, responsive styled icon component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Styled Icon\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/StyledIcon.wrn" + }, + { + "name": "Switch", + "mount": "Switch", + "category": "forms", + "purpose": "Theme-aware, responsive switch component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Switch\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"on\"" + }, + { + "name": "checked", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur"], + "source": "components/Switch.wrn" + }, + { + "name": "Table", + "mount": "Table", + "category": "tables", + "purpose": "Theme-aware, responsive table component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "caption", + "type": "string", + "required": false, + "default": "\"Table\"" + }, + { + "name": "columns", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "rows", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "striped", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["sort", "select", "rowClick"], + "source": "components/table.wrn" + }, + { + "name": "Tabs", + "mount": "Tabs", + "category": "navigation", + "purpose": "Theme-aware, responsive tabs component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Tabs\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "active", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "orientation", + "type": "string", + "required": false, + "default": "\"horizontal\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Tabs.wrn" + }, + { + "name": "Textarea", + "mount": "Textarea", + "category": "forms", + "purpose": "Theme-aware, responsive textarea component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Textarea\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "rows", + "type": "number", + "required": false, + "default": "5" + }, + { + "name": "resize", + "type": "string", + "required": false, + "default": "\"vertical\"" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "minlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "maxlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "invalid"], + "source": "components/Textarea.wrn" + }, + { + "name": "TextLink", + "mount": "TextLink", + "category": "layout", + "purpose": "Styled inline action link with icons, arrows, external state, and disabled handling.", + "props": [ + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Learn more\"" + }, + { + "name": "href", + "type": "string", + "required": false, + "default": "\"#\"" + }, + { + "name": "target", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "rel", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "external", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"start\"" + }, + { + "name": "showArrow", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "underline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["click", "focus", "blur"], + "source": "components/TextLink.wrn" + }, + { + "name": "Timeline", + "mount": "Timeline", + "category": "base", + "purpose": "Theme-aware, responsive timeline component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Timeline\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Timeline.wrn" + }, + { + "name": "TimePicker", + "mount": "TimePicker", + "category": "forms", + "purpose": "Theme-aware, responsive time picker component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Time\"" + }, + { + "name": "hiddenLabel", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"normal\"" + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": "\"icon-[lucide--clock-3]\"" + }, + { + "name": "iconPosition", + "type": "string", + "required": false, + "default": "\"end\"" + }, + { + "name": "helperText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "cornerHint", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "error", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "inline", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "step", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "format", + "type": "string", + "required": false, + "default": "\"24\"" + }, + { + "name": "minuteStep", + "type": "number", + "required": false, + "default": "5" + }, + { + "name": "hours", + "type": "string", + "required": false, + "default": "[\"00\", \"01\", \"02\", \"03\", \"04\", \"05\", \"06\", \"07\", \"08\", \"09\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"20\", \"21\", \"22\", \"23\"]" + }, + { + "name": "minutes", + "type": "string", + "required": false, + "default": "[\"00\", \"05\", \"10\", \"15\", \"20\", \"25\", \"30\", \"35\", \"40\", \"45\", \"50\", \"55\"]" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "focus", "blur", "open", "close", "invalid"], + "source": "components/TimePicker.wrn" + }, + { + "name": "Toast", + "mount": "Toast", + "category": "base", + "purpose": "Theme-aware, responsive toast component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Toast\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["dismiss", "action"], + "source": "components/Toast.wrn" + }, + { + "name": "ToastNotifications", + "mount": "ToastNotifications", + "category": "integrations", + "purpose": "Theme-aware, responsive toast notifications component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Toast Notifications\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["add", "dismiss", "clear", "action"], + "source": "components/ToastNotifications.wrn" + }, + { + "name": "ToggleCount", + "mount": "ToggleCount", + "category": "advanced-forms", + "purpose": "Theme-aware, responsive toggle count component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"segmented\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"billing-cycle\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"monthly\"" + }, + { + "name": "firstValue", + "type": "string", + "required": false, + "default": "\"monthly\"" + }, + { + "name": "firstLabel", + "type": "string", + "required": false, + "default": "\"Monthly\"" + }, + { + "name": "secondValue", + "type": "string", + "required": false, + "default": "\"annual\"" + }, + { + "name": "secondLabel", + "type": "string", + "required": false, + "default": "\"Annual\"" + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "\"Billing frequency\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "currency", + "type": "string", + "required": false, + "default": "\"$\"" + }, + { + "name": "suffix", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "firstValueKey", + "type": "string", + "required": false, + "default": "\"monthly\"" + }, + { + "name": "secondValueKey", + "type": "string", + "required": false, + "default": "\"annual\"" + }, + { + "name": "emptyValue", + "type": "string", + "required": false, + "default": "\"—\"" + }, + { + "name": "align", + "type": "string", + "required": false, + "default": "\"end\"" + }, + { + "name": "fullWidth", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "animate", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "animationDuration", + "type": "number", + "required": false, + "default": "450" + }, + { + "name": "animationSteps", + "type": "number", + "required": false, + "default": "18" + } + ], + "slots": [], + "events": ["change", "toggle"], + "source": "components/ToggleCount.wrn" + }, + { + "name": "TogglePassword", + "mount": "TogglePassword", + "category": "advanced-forms", + "purpose": "Accessible password field with optional show and hide controls.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "\"Password\"" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "\"password\"" + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "\"Enter your password\"" + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "\"current-password\"" + }, + { + "name": "minlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "maxlength", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "pattern", + "type": "string", + "required": false, + "default": "\"(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}\"" + }, + { + "name": "fields", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "visible", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "toggleable", + "type": "boolean", + "required": false, + "default": "true" + }, + { + "name": "toggleMode", + "type": "string", + "required": false, + "default": "\"button\"" + }, + { + "name": "checkboxLabel", + "type": "string", + "required": false, + "default": "\"Show password\"" + }, + { + "name": "showLabel", + "type": "string", + "required": false, + "default": "\"Show password\"" + }, + { + "name": "hideLabel", + "type": "string", + "required": false, + "default": "\"Hide password\"" + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "required", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "invalid", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "helpText", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "validationMessage", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": [], + "events": ["input", "change", "toggle"], + "source": "components/TogglePassword.wrn" + }, + { + "name": "Tooltip", + "mount": "Tooltip", + "category": "overlays", + "purpose": "Theme-aware, responsive tooltip component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Tooltip\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false" + }, + { + "name": "placement", + "type": "string", + "required": false, + "default": "\"bottom\"" + }, + { + "name": "closeLabel", + "type": "string", + "required": false, + "default": "\"Close\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["open", "close"], + "source": "components/tooltip.wrn" + }, + { + "name": "TreeView", + "mount": "TreeView", + "category": "base", + "purpose": "Theme-aware, responsive tree view component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Tree View\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["select", "toggle", "expand", "collapse"], + "source": "components/TreeView.wrn" + }, + { + "name": "Typography", + "mount": "Typography", + "category": "layout", + "purpose": "Theme-aware, responsive typography component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "columns", + "type": "number", + "required": false, + "default": "2" + }, + { + "name": "gap", + "type": "string", + "required": false, + "default": "\"md\"" + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "\"xl\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": [], + "source": "components/Typography.wrn" + }, + { + "name": "WysiwygEditor", + "mount": "WysiwygEditor", + "category": "integrations", + "purpose": "Theme-aware, responsive wysiwyg editor component.", + "props": [ + { + "name": "size", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "color", + "type": "string", + "required": false, + "default": "\"primary\"" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "\"Wysiwyg Editor\"" + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "\"\"" + }, + { + "name": "items", + "type": "string", + "required": false, + "default": "[]" + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": "\"default\"" + }, + { + "name": "class", + "type": "string", + "required": false, + "default": "\"\"" + } + ], + "slots": ["default"], + "events": ["input", "change", "focus", "blur"], + "source": "components/WysiwygEditor.wrn" + } + ] +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/progress.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/progress.wrn new file mode 100644 index 00000000..dea093ca --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/progress.wrn @@ -0,0 +1,17 @@ +component Progress { + props { + size = "default" + color = "primary" + label = "Progress" + value = 50 + max = 100 + showValue = true + class = "" + } + view { +
+
{label}{#if showValue}{value}%{/if}
+ +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/skeleton.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/skeleton.wrn new file mode 100644 index 00000000..3adaf9fd --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/skeleton.wrn @@ -0,0 +1,14 @@ +component Skeleton { + props { + color = "primary" + label = "Loading" + size = "md" + lines = 3 + class = "" + } + view { +
+ {#if "Skeleton" === "Skeleton"}{#each Array(lines).fill(0) as line}{/each}{:else}{/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/spinner.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/spinner.wrn new file mode 100644 index 00000000..bd607734 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/spinner.wrn @@ -0,0 +1,14 @@ +component Spinner { + props { + color = "primary" + label = "Loading" + size = "md" + lines = 3 + class = "" + } + view { +
+ {#if "Spinner" === "Skeleton"}{#each Array(lines).fill(0) as line}{/each}{:else}{/if} +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/table.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/table.wrn new file mode 100644 index 00000000..1f5dc29f --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/table.wrn @@ -0,0 +1,17 @@ +component Table { + props { + @event sort = function + @event select = function + @event rowClick = function + size = "default" + color = "primary" + caption = "Table" + columns = [] + rows = [] + striped = true + class = "" + } + view { +
{#each columns as column}{/each}{#each rows as row}{#each columns as column}{/each}{/each}
{caption}
{column.label}
{row[column.key]}
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/tooltip.wrn b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/tooltip.wrn new file mode 100644 index 00000000..240da14c --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/tooltip.wrn @@ -0,0 +1,21 @@ +component Tooltip { + props { + @event open = function + @event close = function + size = "default" + color = "primary" + title = "Tooltip" + description = "" + open = false + placement = "bottom" + closeLabel = "Close" + class = "" + } + view { +
+
{title}
+ {#if description}

{description}

{/if} + +
+ } +} diff --git a/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ui.test.ts b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ui.test.ts new file mode 100644 index 00000000..19a8b144 --- /dev/null +++ b/.wrnexus-backups/ui-final-3-fix-v2-2026-07-30T13-05-46-108Z/ui.test.ts @@ -0,0 +1,2438 @@ +import { expect, test } from "bun:test"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import { compileWireFile } from "../../compiler/src/index.ts"; +import { mountHtml, renderComponent } from "../../test/src/index.ts"; +import { uiComponentNames, uiComponentsDir, uiComponentPath, uiCss } from "../src/index.ts"; + +test("bundled UI assets are discoverable and readable", () => { + expect(uiComponentNames()).toContain("Button"); + expect(uiComponentNames()).toContain("Accordion"); + expect(uiComponentNames()).toContain("DataTable"); + expect(uiComponentNames()).toContain("WysiwygEditor"); + expect(readFileSync(uiComponentPath("Button"), "utf8")).toContain("component Button"); + expect(uiCss()).toContain("--wire-"); +}); + +test("generated component reference documents every bundled component and its props", () => { + const reference = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-reference.json"), "utf8"), + ) as { count: number; components: Array<{ name: string; props: Array<{ name: string }> }> }; + const catalog = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-catalog.json"), "utf8"), + ) as { components: Array<{ name: string }> }; + expect(reference.count).toBe(uiComponentNames().length); + expect(reference.count).toBe(108); + expect(reference.components.map((component) => component.name)).toEqual( + expect.arrayContaining(uiComponentNames()), + ); + expect(catalog.components.map((component) => component.name).sort()).toEqual( + uiComponentNames().sort(), + ); + expect(reference.components.find((component) => component.name === "Button")?.props).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "label" }), + expect.objectContaining({ name: "as" }), + ]), + ); + expect( + reference.components + .find((component) => component.name === "PinInput") + ?.props.find((prop) => prop.name === "length"), + ).toEqual(expect.objectContaining({ default: "4" })); +}); + +test("interactive components expose their must-have public event contracts", () => { + const reference = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-reference.json"), "utf8"), + ) as { components: Array<{ name: string; events: string[] }> }; + const eventsByComponent = new Map( + reference.components.map((component) => [component.name, component.events]), + ); + const requiredEvents: Record = { + Button: ["click", "focus", "blur"], + Input: ["input", "change", "focus", "blur", "invalid"], + Select: ["input", "change", "open", "close"], + Checkbox: ["input", "change", "focus", "blur", "invalid"], + ColorPicker: ["input", "change", "focus", "blur"], + FileInput: ["input", "change", "focus", "blur", "select", "clear", "invalid"], + InputGroup: ["input", "change", "focus", "blur", "submit", "action"], + Radio: ["input", "change", "focus", "blur", "invalid"], + RangeSlider: ["input", "change", "focus", "blur"], + Switch: ["input", "change", "focus", "blur"], + Textarea: ["input", "change", "focus", "blur", "invalid"], + TimePicker: ["input", "change", "focus", "blur", "open", "close", "invalid"], + Accordion: ["change", "open", "close"], + Modal: ["open", "close", "cancel", "confirm"], + DataTable: ["sort", "select", "change", "rowClick", "pageChange"], + FileUpload: ["select", "upload", "progress", "success", "error", "cancel", "remove"], + WysiwygEditor: ["input", "change", "focus", "blur"], + }; + + for (const [component, events] of Object.entries(requiredEvents)) { + expect(eventsByComponent.get(component)).toEqual(expect.arrayContaining(events)); + } +}); + +test("component reference contains only explicitly declared public events", () => { + const reference = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-reference.json"), "utf8"), + ) as { components: Array<{ name: string; events: string[] }> }; + + for (const component of reference.components) { + const source = readFileSync(uiComponentPath(component.name), "utf8"); + const declaredEvents = [ + ...source.matchAll(/@event\s+([A-Za-z][A-Za-z0-9_]*)\s*=\s*function/g), + ].map((match) => match[1]); + expect(component.events).toEqual([...new Set(declaredEvents)]); + } +}); + +test("bundled components do not duplicate another component implementation", () => { + const implementations = new Map(); + + for (const name of uiComponentNames()) { + const source = readFileSync(uiComponentPath(name), "utf8") + .replace(/^component\s+[A-Za-z0-9_]+/, "component __NAME__") + .replace(/\r\n/g, "\n") + .trim(); + expect(implementations.get(source)).toBeUndefined(); + implementations.set(source, name); + } +}); + +test("removed duplicate aliases have valid canonical migration targets", () => { + const migration = JSON.parse( + readFileSync(join(uiComponentsDir(), "..", "component-migrations.json"), "utf8"), + ) as { removedCount: number; replacements: Record }; + const names = new Set(uiComponentNames()); + + expect(Object.keys(migration.replacements)).toHaveLength(migration.removedCount); + expect(migration.removedCount).toBe(0); + for (const [removed, replacement] of Object.entries(migration.replacements)) { + expect(names.has(removed)).toBe(false); + expect(names.has(replacement)).toBe(true); + } +}); + +test("screenshot-directed canonical components are bundled", () => { + const required = [ + "Container", + "Columns", + "Grid", + "Typography", + "Button", + "Accordion", + "Alert", + "Avatar", + "Card", + "Carousel", + "DatePicker", + "Progress", + "Spinner", + "Timeline", + "Navbar", + "Tabs", + "Sidebar", + "Breadcrumb", + "Pagination", + "Stepper", + "Input", + "Textarea", + "Checkbox", + "Radio", + "Switch", + "Select", + "ComboBox", + "TimePicker", + "Modal", + "Drawer", + "Popover", + "Tooltip", + "Table", + "DataTable", + "Chart", + "FileUpload", + "Map", + "WysiwygEditor", + ]; + + expect(uiComponentNames()).toEqual(expect.arrayContaining(required)); +}); + +test("navbar supports brands, nested menus, actions, utility slots, and public events", () => { + const source = readFileSync(uiComponentPath("Navbar"), "utf8"); + expect(source).toContain('slot name="topbar"'); + expect(source).toContain('slot name="actions"'); + expect(source).toContain("brand = {}"); + expect(source).toContain("actions = []"); + expect(source).toContain("openOnHover = false"); + expect(source).toContain('maxWidth = "full"'); + expect(source).toContain("item.children"); + expect(source).toContain("child.children"); + expect(source).toContain("wire-navbar__dropdown--{item.type || 'dropdown'}"); + for (const event of ["toggle", "open", "close", "select", "action"]) { + expect(source).toContain(`@event ${event} = function`); + } +}); + +test("auth form uses package schemas, disables native validation, and renders a full-width submit control", async () => { + const source = readFileSync(uiComponentPath("AuthForm"), "utf8"); + expect(source).toContain('return "auth-login"'); + expect(source).toContain('data-schema="{schemaName()}"'); + expect(source).toContain('data-wrnexus-runtime="auth"'); + expect(source).toContain('novalidate="true"'); + expect(source).toContain('fullWidth="true"'); + + const html = await renderComponent(source, { mode: "sign-in" }); + expect(html).toContain('data-schema="auth-login"'); + expect(html).toContain('data-wrnexus-runtime="auth"'); + expect(html).toContain("novalidate"); + expect(html).toContain("wire-auth-form__submit"); + expect(html).toContain('fullWidth="true"'); +}); + +test("footer supports typed entries, responsive columns, pre/post slots, and events", () => { + const source = readFileSync(uiComponentPath("Footer"), "utf8"); + expect(source).toContain('slot name="pre-footer"'); + expect(source).toContain('slot name="post-footer"'); + expect(source).toContain('slot name="copyright-left"'); + expect(source).toContain('slot name="copyright-right"'); + expect(source).toContain('item.type === "header"'); + expect(source).toContain("wire-footer--columns-{columns}"); + expect(source).toContain("@event select = function"); + expect(source).toContain("@event action = function"); +}); + +test("navbar renders a brand, nested dropdowns, mega groups, and actions", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Navbar"), "utf8"), { + brand: { + label: "Police Management System", + description: "Public portal", + href: "/", + }, + items: [ + { + label: "Services", + type: "dropdown", + children: [{ label: "Reports", href: "/reports" }], + }, + { + label: "Safety", + type: "mega", + columns: 2, + children: [ + { + label: "Resources", + children: [{ label: "Guidance", href: "/guidance" }], + }, + ], + }, + ], + actions: [{ label: "Sign in", href: "/login", variant: "primary" }], + }); + + expect(html).toContain("Police Management System"); + expect(html).toContain("Public portal"); + expect(html).toContain("Reports"); + expect(html).toContain("Guidance"); + expect(html).toContain("wire-navbar__dropdown--mega"); + expect(html).toContain("data-wrn-navbar"); + expect(html).toContain('name="wire-navbar-menu"'); + expect(html).toContain("Sign in"); +}); + +test("navbar closes sibling menus and menus close after an outside pointer press", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Navbar"), "utf8"), { + items: [ + { label: "Services", children: [{ label: "Reports", href: "/reports" }] }, + { label: "Safety", children: [{ label: "Guidance", href: "/guidance" }] }, + ], + }); + const dom = mountHtml(html); + const menus = Array.from(dom.querySelectorAll(".wire-navbar__dropdown")) as HTMLDetailsElement[]; + + menus[0].open = true; + menus[0].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("toggle", { bubbles: false }), + ); + menus[1].open = true; + menus[1].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("toggle", { bubbles: false }), + ); + expect(menus[0].open).toBe(false); + expect(menus[1].open).toBe(true); + + dom.document.body.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("pointerdown", { bubbles: true }), + ); + expect(menus[1].open).toBe(false); +}); + +test("navbar optionally opens menus on hover and renders full-width mode", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Navbar"), "utf8"), { + openOnHover: true, + maxWidth: "full", + items: [{ label: "Services", children: [{ label: "Reports", href: "/reports" }] }], + }); + const dom = mountHtml(html); + const navbar = dom.querySelector("[data-wrn-navbar]"); + const menu = dom.querySelector(".wire-navbar__dropdown") as HTMLDetailsElement; + + expect(navbar?.classList.contains("wire-navbar--width-full")).toBe(true); + expect(navbar?.getAttribute("data-open-on-hover")).toBe("true"); + menu.dispatchEvent(new (dom.window as { Event: typeof Event }).Event("pointerenter")); + expect(menu.open).toBe(true); + menu.dispatchEvent(new (dom.window as { Event: typeof Event }).Event("pointerleave")); + expect(menu.open).toBe(true); + await new Promise((resolve) => setTimeout(resolve, 280)); + expect(menu.open).toBe(false); +}); + +test("navbar hover menu stays open while the pointer crosses into its panel", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Navbar"), "utf8"), { + openOnHover: true, + items: [{ label: "Services", children: [{ label: "Reports", href: "/reports" }] }], + }); + const dom = mountHtml(html); + const menu = dom.querySelector(".wire-navbar__dropdown") as HTMLDetailsElement; + const panel = dom.querySelector(".wire-navbar__panel") as HTMLElement; + const DomEvent = (dom.window as { Event: typeof Event }).Event; + + menu.dispatchEvent(new DomEvent("pointerenter")); + menu.dispatchEvent(new DomEvent("pointerleave")); + panel.dispatchEvent(new DomEvent("pointerenter", { bubbles: true })); + await new Promise((resolve) => setTimeout(resolve, 280)); + + expect(menu.open).toBe(true); +}); + +test("preference switcher keeps only one popover open and closes outside", async () => { + const html = await renderComponent( + readFileSync(uiComponentPath("PreferenceSwitcher"), "utf8"), + {}, + ); + const dom = mountHtml(html); + const menus = Array.from(dom.querySelectorAll(".wire-preferences__menu")) as HTMLDetailsElement[]; + const DomEvent = (dom.window as { Event: typeof Event }).Event; + + menus[0].open = true; + menus[0].dispatchEvent(new DomEvent("toggle")); + menus[1].open = true; + menus[1].dispatchEvent(new DomEvent("toggle")); + expect(menus[0].open).toBe(false); + expect(menus[1].open).toBe(true); + + dom.document.body.dispatchEvent(new DomEvent("pointerdown", { bubbles: true })); + expect(menus[1].open).toBe(false); +}); + +test("sidebar renders compact grouped submenu navigation and a mobile drawer trigger", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Sidebar"), "utf8"), { + label: "Operations", + orientation: "vertical", + items: [ + { label: "Dashboard", href: "/dashboard", value: "dashboard" }, + { + label: "Case management", + children: [ + { label: "Assigned cases", href: "/cases", value: "cases" }, + { label: "Evidence", href: "/evidence", value: "evidence" }, + ], + }, + ], + }); + + expect(html).toContain("wire-sidebar-toggle"); + expect(html).toContain("wire-sidebar-backdrop"); + expect(html).toContain("wire-sidebar-group"); + expect(html).toContain("Assigned cases"); + expect(html).toContain("Evidence"); +}); + +test("dropdown renders slotted account triggers, menu structure, and public events", async () => { + const source = readFileSync(uiComponentPath("Dropdown"), "utf8"); + const html = await renderComponent(source, { + label: "Account menu", + items: [ + { type: "header", label: "Account" }, + { label: "Profile", href: "/profile", icon: "icon-[lucide--user]" }, + { type: "divider" }, + { label: "Sign out", href: "/logout", danger: true }, + ], + }); + + expect(source).toContain('slot name="trigger"'); + expect(source).toContain("@event select = function"); + expect(html).toContain("wire-dropdown__panel"); + expect(html).toContain("Profile"); + expect(html).toContain("wire-dropdown__item--danger"); +}); + +test("footer renders header and link entries with the requested column count", async () => { + const html = await renderComponent(readFileSync(uiComponentPath("Footer"), "utf8"), { + columns: 4, + items: [ + { type: "header", label: "Support" }, + { type: "link", label: "Contact", href: "/contact" }, + ], + copyright: "Public service platform", + }); + + expect(html).toContain("wire-footer--columns-4"); + expect(html).toContain("wire-footer__column"); + expect(html).toContain("wire-footer__column-links"); + expect(html).toContain("wire-footer__heading"); + expect(html).toContain("Support"); + expect(html).toContain('href="/contact"'); + expect(html).toContain("Public service platform"); +}); + +test("component-system CSS includes responsive, theme-token, focus, and reduced-motion rules", () => { + const css = uiCss(); + expect(css).toContain("@media (max-width: 768px)"); + expect(css).toContain("@media (max-width: 480px)"); + expect(css).toContain("@media (prefers-reduced-motion: reduce)"); + expect(css).toContain(":focus-visible"); + expect(css).toContain("var(--wire-color-surface)"); + expect(css).toContain("min-height: 44px"); + expect(css).toContain("--wire-motion-base"); + expect(css).toContain("--wire-ease-emphasized"); + expect(css).toContain("@keyframes wire-component-enter"); + expect(css).toContain("@keyframes wire-dialog-enter"); + expect(css).toContain("@media (hover: hover) and (pointer: fine)"); + expect(css).toContain("--color-violet-600: var(--wire-color-primary)"); + expect(css).toContain("--color-blue-600: var(--wire-color-info)"); + expect(css).toContain("--color-red-600: var(--wire-color-danger)"); + expect(css).toMatch(/:root\s*\{[^}]*--color-violet-600: var\(--wire-color-primary\)/s); + expect(css).toContain(".wire-bg-primary"); + expect(css).toContain(".wire-text-muted"); + expect(css).toContain(".wire-visually-hidden"); + expect(css).toContain(".wire-next--field"); + expect(css).toContain(".wire-next--table"); + expect(css).toContain('[data-show="false"]'); + expect(css).toContain("display: none !important"); + expect(css).toMatch( + /\.wire-navbar__brand-copy strong\s*\{[^}]*font-size: 0\.9rem;[^}]*font-weight: 600;/s, + ); + expect(css).toMatch( + /\.wire-navbar__menu-link,[\s\S]*?font-size: 0\.8125rem;[\s\S]*?font-weight: 500;/, + ); + expect(css).toMatch( + /\.wire-footer__heading\s*\{[^}]*font-size: 0\.8125rem;[^}]*font-weight: 600;/s, + ); + expect(css).toMatch(/\.wire-footer__link\s*\{[^}]*font-size: 0\.8125rem;[^}]*font-weight: 400;/s); +}); + +test("component boundaries have no default margins and expose the canonical class prop", () => { + for (const name of uiComponentNames()) { + const source = readFileSync(uiComponentPath(name), "utf8"); + const root = source.match(/view\s*\{\s*<[A-Za-z][^>]*>/)?.[0] ?? ""; + const classes = root.match(/\bclass="([^"]*)"/)?.[1]?.split(/\s+/) ?? []; + expect(classes.filter((token) => /^-?m[trblxy]?-/.test(token))).toEqual([]); + expect(source).toMatch(/^\s*class\s*(?::[^=\r\n]+)?=/m); + expect(source).not.toMatch(/^\s*className\s*(?::[^=\r\n]+)?=/m); + expect(root).toContain("{class}"); + } +}); + +test("every component exposes universal color and size configuration", () => { + for (const name of uiComponentNames()) { + const source = readFileSync(uiComponentPath(name), "utf8"); + expect(source).toMatch(/^\s+color\s*=/m); + expect(source).toMatch(/^\s+size\s*=/m); + } +}); + +// test("component markup keeps user-facing content and data behind props", () => { +// for (const name of uiComponentNames()) { +// const source = readFileSync(uiComponentPath(name), "utf8"); +// const view = source.slice(source.indexOf("view {")); +// const literalText = [...view.matchAll(/>([^<>{}]*[A-Za-z][^<>{}]*) match[1].trim()) +// .filter(Boolean); +// const literalAccessibleText = [ +// ...view.matchAll(/\b(?:aria-label|title|placeholder|alt)="([^"{}]*[A-Za-z][^"{}]*)"/g), +// ]; +// const literalDataAttributes = [ +// ...view.matchAll(/\b(?:href|src|action|value)="([^"{}]+)"/g), +// ].filter((match) => !/^(?:true|false|on)$/.test(match[1])); + +// expect(literalText).toEqual([]); +// expect(literalAccessibleText).toEqual([]); +// expect(literalDataAttributes).toEqual([]); +// } +// }); + +test("layout boundaries do not add default padding", () => { + for (const name of ["Container", "Columns", "Grid", "LayoutSplitter", "Typography"]) { + const source = readFileSync(uiComponentPath(name), "utf8"); + const root = source.match(/view\s*\{\s*<[A-Za-z][^>]*>/)?.[0] ?? ""; + const classes = root.match(/\bclass="([^"]*)"/)?.[1]?.split(/\s+/) ?? []; + expect(classes.filter((token) => /^p[trblxy]?-/.test(token))).toEqual([]); + } +}); + +test("every bundled UI component compiles", () => { + for (const name of uiComponentNames()) { + const path = uiComponentPath(name); + expect(() => compileWireFile(readFileSync(path, "utf8"), path)).not.toThrow(); + } +}); + +test("icon buttons expose their accessible label as a hover and focus tooltip", () => { + const button = readFileSync(uiComponentPath("Button"), "utf8"); + expect(button).toContain('class="wire-btn__tooltip"'); + expect(button).toContain("{ariaLabel || label}"); + expect(uiCss()).toContain(".wire-btn:hover > .wire-btn__tooltip"); + expect(uiCss()).toContain(".wire-btn:focus-visible > .wire-btn__tooltip"); +}); + +test("button links navigate by default and only download when the native attribute is passed", () => { + const button = readFileSync(uiComponentPath("Button"), "utf8"); + expect(button).not.toMatch(/^\s+download\s*=/m); + expect(button).not.toContain('download="{download}"'); + expect(button).toContain("{...attrs}"); +}); + +test("button group renders connected actions and emits select and change events", async () => { + const source = readFileSync(uiComponentPath("ButtonGroup"), "utf8"); + const html = await renderComponent(source, { + items: [ + { label: "Profile", value: "profile" }, + { label: "Settings", value: "settings" }, + { label: "Messages", value: "messages", disabled: true }, + ], + value: "profile", + selectable: true, + size: "sm", + variant: "outline", + ariaLabel: "Account views", + }); + const dom = mountHtml(html); + const group = dom.querySelector(".wire-next--button-group") as HTMLElement; + const buttons = [...dom.querySelectorAll(".wire-next--button-group > button")]; + const events: Array<{ name: string; detail: unknown }> = []; + + for (const name of ["select", "change"]) { + group.addEventListener(name, (event) => + events.push({ name, detail: (event as CustomEvent).detail }), + ); + } + + expect(group.getAttribute("role")).toBe("group"); + expect(group.getAttribute("aria-label")).toBe("Account views"); + expect(group.getAttribute("data-size")).toBe("sm"); + expect(buttons).toHaveLength(3); + expect(buttons[0]?.getAttribute("aria-pressed")).toBe("true"); + expect(buttons[2]?.hasAttribute("disabled")).toBe(true); + + (buttons[1] as HTMLButtonElement).click(); + + expect(buttons[0]?.getAttribute("aria-pressed")).toBe("false"); + expect(buttons[1]?.getAttribute("aria-pressed")).toBe("true"); + expect(events.map((event) => event.name)).toEqual(["select", "change"]); + expect((events[1]?.detail as { value: string }).value).toBe("settings"); + expect((events[1]?.detail as { previousValue: string }).previousValue).toBe("profile"); +}); + +test("button group supports vertical, responsive, detached, and toolbar layouts", async () => { + const source = readFileSync(uiComponentPath("ButtonGroup"), "utf8"); + const html = await renderComponent(source, { + items: [{ label: "Bold", icon: "icon-[lucide--bold]" }], + orientation: "vertical", + responsive: true, + attached: false, + toolbar: true, + ariaLabel: "Formatting", + }); + const dom = mountHtml(html); + const group = dom.querySelector(".wire-next--button-group") as HTMLElement; + + expect(group.getAttribute("role")).toBe("toolbar"); + expect(group.getAttribute("aria-orientation")).toBe("vertical"); + expect(group.getAttribute("data-responsive")).toBe("true"); + expect(group.getAttribute("data-attached")).toBe("false"); + expect(group.querySelector('[class*="icon-[lucide--bold]"]')).not.toBeNull(); + + const css = uiCss(); + expect(css).toContain('.wire-next--button-group[data-orientation="vertical"]'); + expect(css).toContain('.wire-next--button-group[data-responsive="true"]'); + expect(css).toContain('.wire-next--button-group[data-attached="false"]'); +}); + +test("every bundled UI component forwards undeclared native attributes", () => { + for (const name of uiComponentNames()) { + const path = uiComponentPath(name); + const output = compileWireFile(readFileSync(path, "utf8"), path); + expect(output).toContain("${__wireSpreadAttrs(__attrs)}"); + } +}); + +test("accordion coordinates single-open sections and emits open, close, and change events", async () => { + const source = readFileSync(uiComponentPath("Accordion"), "utf8"); + const html = await renderComponent(source, { + id: "faq", + defaultOpen: ["first"], + items: [ + { value: "first", label: "First", content: "First content" }, + { value: "second", label: "Second", content: "Second content" }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-accordion]") as HTMLElement; + const events: string[] = []; + for (const name of ["open", "close", "change"]) { + root.addEventListener(name, () => events.push(name)); + } + + expect(dom.querySelector("#faq-trigger-0")?.getAttribute("aria-expanded")).toBe("true"); + expect(dom.querySelector("#faq-panel-0")?.getAttribute("aria-hidden")).toBe("false"); + + (dom.querySelector("#faq-trigger-1") as HTMLButtonElement).click(); + + expect(dom.querySelector("#faq-trigger-0")?.getAttribute("aria-expanded")).toBe("false"); + expect(dom.querySelector("#faq-trigger-1")?.getAttribute("aria-expanded")).toBe("true"); + expect(events).toEqual(["open", "change"]); + + (dom.querySelector("#faq-trigger-1") as HTMLButtonElement).click(); + expect(dom.querySelector("#faq-trigger-1")?.getAttribute("aria-expanded")).toBe("false"); + expect(events).toEqual(["open", "change", "close", "change"]); +}); + +test("accordion supports always-open, nested, and disabled sections", async () => { + const source = readFileSync(uiComponentPath("Accordion"), "utf8"); + const html = await renderComponent(source, { + id: "nested-faq", + alwaysOpen: true, + defaultOpen: ["first", "first.child"], + items: [ + { + value: "first", + label: "First", + content: "First content", + children: [{ value: "child", label: "Child", content: "Child content" }], + }, + { value: "second", label: "Second", content: "Second content" }, + { value: "third", label: "Third", content: "Third content", disabled: true }, + ], + }); + const dom = mountHtml(html); + + expect(dom.querySelector("#nested-faq-trigger-0")?.getAttribute("aria-expanded")).toBe("true"); + expect(dom.querySelector("#nested-faq-trigger-0-0")?.getAttribute("aria-expanded")).toBe("true"); + + (dom.querySelector("#nested-faq-trigger-1") as HTMLButtonElement).click(); + expect(dom.querySelector("#nested-faq-trigger-0")?.getAttribute("aria-expanded")).toBe("true"); + expect(dom.querySelector("#nested-faq-trigger-1")?.getAttribute("aria-expanded")).toBe("true"); + expect((dom.querySelector("#nested-faq-trigger-2") as HTMLButtonElement).disabled).toBe(true); +}); + +test("accordion chevrons use a consistent icon instead of a font glyph", () => { + const source = readFileSync(uiComponentPath("Accordion"), "utf8"); + + expect(source).toContain("icon-[lucide--chevron-down]"); + expect(source).not.toContain('return "⌄"'); +}); + +test("alert renders structured content, lists, actions, and accessible semantics", async () => { + const source = readFileSync(uiComponentPath("Alert"), "utf8"); + const html = await renderComponent(source, { + title: "Cannot save changes", + description: "Review the following fields.", + color: "danger", + variant: "soft", + showIcon: true, + items: [{ label: "Email is required" }, { label: "Phone number is invalid" }], + actions: [{ label: "Review form", href: "#form" }], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-alert]") as HTMLElement; + let detail: Record | undefined; + root.addEventListener("action", (event) => { + detail = (event as unknown as CustomEvent>).detail; + }); + + expect(root.getAttribute("role")).toBe("alert"); + expect(root.getAttribute("aria-live")).toBe("polite"); + expect(root.dataset.color).toBe("danger"); + expect(dom.querySelectorAll(".wire-next__alert-body li").map((node) => node.textContent)).toEqual( + ["Email is required", "Phone number is invalid"], + ); + + (dom.querySelector(".wire-next__alert-actions a") as HTMLAnchorElement).click(); + expect(detail).toMatchObject({ + component: "Alert", + action: { label: "Review form", href: "#form" }, + }); +}); + +test("dismissible alert hides itself and emits dismiss details", async () => { + const source = readFileSync(uiComponentPath("Alert"), "utf8"); + const html = await renderComponent(source, { + title: "Update available", + description: "Install the latest version.", + dismissible: true, + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-alert]") as HTMLElement; + let dismissed = false; + root.addEventListener("dismiss", () => { + dismissed = true; + }); + + (dom.querySelector(".wire-next__alert-dismiss") as HTMLButtonElement).click(); + + expect(dismissed).toBe(true); + expect(root.getAttribute("aria-hidden")).toBe("true"); + expect(root.style.display).toBe("none"); +}); + +test("solid alert palettes preserve readable foregrounds and compact inline layout", () => { + const css = uiCss(); + + expect(css).toContain('.wire-next--alert[data-color="secondary"]'); + expect(css).toContain("--wire-alert-color: #737373"); + expect(css).toContain( + ".wire-next--alert-compact:not(:has(.wire-next__alert-icon)):not(:has(.wire-next__alert-dismiss))", + ); + expect(css).toContain(".wire-next--alert-compact .wire-next__alert-body > p"); + expect(css).toContain("color: currentColor"); +}); + +test("alert exposes configurable radius and elevation treatments", async () => { + const source = readFileSync(uiComponentPath("Alert"), "utf8"); + const html = await renderComponent(source, { + title: "Elevated alert", + radius: "xl", + shadow: "lg", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-alert]") as HTMLElement; + const css = uiCss(); + + expect(root.dataset.radius).toBe("xl"); + expect(root.dataset.shadow).toBe("lg"); + expect(css).toContain('.wire-next--alert[data-radius="xl"]'); + expect(css).toContain('.wire-next--alert[data-shadow="lg"]'); + expect(css).toContain("border-radius: calc(var(--wire-radius, 0.75rem) * 1.75)"); + expect(css).toContain("0 20px 48px color-mix(in srgb, #000 24%, transparent)"); +}); + +test("avatar renders images, fallbacks, presence, badges, tooltips, and media copy", async () => { + const source = readFileSync(uiComponentPath("Avatar"), "utf8"); + const imageHtml = await renderComponent(source, { + src: "/avatar.jpg", + alt: "Avery Chen", + shape: "rounded", + statusPosition: "top", + status: "online", + statusLabel: "Online", + tooltip: "Avery Chen · Online", + }); + const imageDom = mountHtml(imageHtml); + const imageRoot = imageDom.querySelector("[data-wrn-avatar]") as HTMLElement; + + expect(imageRoot.querySelector('img[alt="Avery Chen"]')).not.toBeNull(); + expect(imageRoot.querySelector('[data-status="online"]')?.getAttribute("aria-label")).toBe( + "Online", + ); + expect(imageRoot.querySelector('[role="tooltip"]')?.textContent).toContain("Avery Chen"); + + const initialsDom = mountHtml( + await renderComponent(source, { + initials: "MW", + color: "success", + badgeIcon: "icon-[lucide--message-square]", + badgeLabel: "Messaging account", + name: "Mark Wanner", + description: "mark@example.com", + }), + ); + expect(initialsDom.querySelector(".wire-next__avatar-initials")?.textContent).toBe("MW"); + expect(initialsDom.querySelector(".wire-next__avatar-badge")?.getAttribute("aria-label")).toBe( + "Messaging account", + ); + expect(initialsDom.querySelector(".wire-next__avatar-copy")?.textContent).toContain( + "mark@example.com", + ); + + const placeholderDom = mountHtml(await renderComponent(source, { size: "sm" })); + expect(placeholderDom.querySelector(".wire-next__avatar-placeholder")).not.toBeNull(); + expect(source).not.toContain("items ="); + expect(uiCss()).toContain('.wire-next__avatar-wrap[data-shape="rounded"]'); +}); + +test("avatar group limits members and opens an accessible overflow menu", async () => { + const source = readFileSync(uiComponentPath("AvatarGroup"), "utf8"); + const html = await renderComponent(source, { + maxVisible: 2, + borderColor: "#2583ff", + items: [ + { src: "/one.svg", name: "One" }, + { initials: "TW", name: "Two" }, + { initials: "TH", name: "Three" }, + { initials: "FO", name: "Four" }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-avatar-group]") as HTMLElement; + const button = root.querySelector( + ".wire-next__avatar-group-overflow-button", + ) as HTMLButtonElement; + let eventDetail: { open: boolean; hiddenCount: number } | undefined; + root.addEventListener("overflow", (event) => { + eventDetail = (event as CustomEvent).detail; + }); + + expect(root.querySelectorAll(".wire-next__avatar-group-member")).toHaveLength(2); + expect(button.textContent?.trim()).toBe("+2"); + expect(button.getAttribute("aria-expanded")).toBe("false"); + expect(root.getAttribute("style")).toContain("#2583ff"); + expect(root.querySelector(".wire-next__avatar-group-menu")?.getAttribute("data-show")).toBe( + "false", + ); + + button.click(); + + expect( + dom.querySelector(".wire-next__avatar-group-overflow-button")?.getAttribute("aria-expanded"), + ).toBe("true"); + expect(dom.querySelectorAll('[role="menuitem"]')).toHaveLength(2); + expect(dom.querySelector(".wire-next__avatar-group-menu")?.getAttribute("data-show")).toBe( + "true", + ); + expect(eventDetail).toEqual(expect.objectContaining({ open: true, hiddenCount: 2 })); + expect(uiCss()).toContain('.wire-next--avatar-group[data-layout="grid"]'); +}); + +test("badge supports rich content, anchored placement, animation, and dismissal", async () => { + const source = readFileSync(uiComponentPath("Badge"), "utf8"); + const html = await renderComponent(source, { + label: "Christina", + color: "success", + variant: "soft", + icon: "icon-[lucide--circle-check]", + dot: true, + avatarSrc: "/avatar.svg", + avatarAlt: "Christina", + dismissible: true, + animated: true, + anchorIcon: "icon-[lucide--bell]", + anchorLabelText: "Open notifications", + placement: "top-right", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-badge]") as HTMLElement; + let dismissed = ""; + root.addEventListener("dismiss", (event) => { + dismissed = (event as CustomEvent).detail.label; + }); + + expect(root.dataset.placement).toBe("top-right"); + expect(root.querySelector(".wire-next__badge-anchor")?.getAttribute("aria-label")).toBe( + "Open notifications", + ); + expect(root.querySelector('img[alt="Christina"]')).not.toBeNull(); + expect(root.querySelector(".wire-next__badge-dot")).not.toBeNull(); + expect(root.querySelector(".wire-next__badge-ping")).not.toBeNull(); + + (root.querySelector(".wire-next__badge-dismiss") as HTMLButtonElement).click(); + + expect(dom.querySelector("[data-wrn-badge]")?.getAttribute("data-show")).toBe("false"); + expect(dismissed).toBe("Christina"); + expect(source).not.toContain("items ="); + expect(uiCss()).toContain("@keyframes wire-badge-ping"); +}); + +test("blockquote renders semantic quote and citation content", async () => { + const source = readFileSync(uiComponentPath("Blockquote"), "utf8"); + const html = await renderComponent(source, { + quote: "Design is intelligence made visible.", + citation: "Alina Wheeler", + citationTitle: "Author, Designing Brand Identity", + citationUrl: "https://example.com/source", + avatarSrc: "/authors/alina.jpg", + avatarAlt: "Alina Wheeler", + size: "lg", + color: "info", + align: "center", + }); + const dom = mountHtml(html); + const figure = dom.querySelector("figure") as HTMLElement; + const quote = figure.querySelector("blockquote"); + const citation = figure.querySelector("figcaption"); + + expect(figure.getAttribute("data-size")).toBe("lg"); + expect(figure.getAttribute("data-color")).toBe("info"); + expect(figure.getAttribute("data-align")).toBe("center"); + expect(quote?.getAttribute("cite")).toBe("https://example.com/source"); + expect(quote?.textContent).toContain("Design is intelligence made visible."); + expect(quote?.querySelector('[aria-hidden="true"]')?.textContent).toBe("“"); + expect(citation?.querySelector("cite a")?.textContent).toBe("Alina Wheeler"); + expect(citation?.textContent).toContain("Author, Designing Brand Identity"); + expect(citation?.querySelector("img")?.getAttribute("alt")).toBe("Alina Wheeler"); +}); + +test("blockquote supports bordered, right-aligned, non-italic, and slotted quotes", async () => { + const source = readFileSync(uiComponentPath("Blockquote"), "utf8"); + const html = await renderComponent(source, { + quote: "", + variant: "bordered", + align: "right", + italic: false, + quoteMark: false, + }); + const dom = mountHtml(html); + const figure = dom.querySelector("figure") as HTMLElement; + + expect(figure.getAttribute("data-variant")).toBe("bordered"); + expect(figure.getAttribute("data-align")).toBe("right"); + expect(figure.getAttribute("data-italic")).toBe("false"); + expect(figure.querySelector(".wire-next__blockquote-mark")).toBeNull(); + expect(source).toContain(""); + + const css = uiCss(); + expect(css).toContain('.wire-next--blockquote[data-variant="bordered"]'); + expect(css).toContain('.wire-next--blockquote[data-align="center"]'); + expect(css).toContain("--wire-blockquote-font-size"); +}); + +test("card renders structured media, header, body, action, and footer content", async () => { + const source = readFileSync(uiComponentPath("Card"), "utf8"); + const html = await renderComponent(source, { + title: "Release notes", + subtitle: "Version 2.4", + description: "A structured card description.", + header: "Featured", + footer: "Updated today", + imageSrc: "/release.jpg", + imageAlt: "Release preview", + actionLabel: "Read more", + actionHref: "/releases/2-4", + size: "lg", + color: "info", + }); + const dom = mountHtml(html); + const card = dom.querySelector(".wire-next--card") as HTMLElement; + + expect(card.getAttribute("data-size")).toBe("lg"); + expect(card.getAttribute("data-color")).toBe("info"); + expect(card.querySelector("article")).not.toBeNull(); + expect(card.querySelector("header")?.textContent).toContain("Featured"); + expect(card.querySelector("img")?.getAttribute("alt")).toBe("Release preview"); + expect(card.querySelector("h3")?.textContent).toBe("Release notes"); + expect(card.querySelector(".wire-next__card-subtitle")?.textContent).toBe("Version 2.4"); + expect(card.querySelector(".wire-next__card-action")?.getAttribute("href")).toBe("/releases/2-4"); + expect(card.querySelector("footer")?.textContent).toContain("Updated today"); +}); + +test("card navigation, header actions, and dismissal emit public events", async () => { + const source = readFileSync(uiComponentPath("Card"), "utf8"); + const html = await renderComponent(source, { + title: "Account", + header: "Card actions", + navigation: [ + { label: "Profile", value: "profile" }, + { label: "Security", value: "security" }, + ], + activeNav: "profile", + headerActions: [{ label: "Refresh", icon: "icon-[lucide--refresh-cw]" }], + dismissible: true, + }); + const dom = mountHtml(html); + const card = dom.querySelector(".wire-next--card") as HTMLElement; + const events: string[] = []; + + for (const name of ["navigate", "action", "dismiss"]) { + card.addEventListener(name, () => events.push(name)); + } + + (dom.querySelectorAll(".wire-next__card-tabs button")[1] as HTMLButtonElement).click(); + (dom.querySelector(".wire-next__card-header-actions button") as HTMLButtonElement).click(); + (dom.querySelectorAll(".wire-next__card-header-actions button")[1] as HTMLButtonElement).click(); + + expect(events).toEqual(["navigate", "action", "dismiss"]); + expect(dom.querySelector(".wire-next__card-panel")?.hasAttribute("hidden")).toBe(true); +}); + +test("card supports overlays, horizontal media, groups, alerts, empty and scrolling panels", async () => { + const source = readFileSync(uiComponentPath("Card"), "utf8"); + const overlay = mountHtml( + await renderComponent(source, { + title: "Overlay", + description: "Overlay copy", + imageSrc: "/overlay.jpg", + imagePosition: "overlay", + }), + ); + const group = mountHtml( + await renderComponent(source, { + items: [ + { title: "First", description: "First card" }, + { title: "Second", description: "Second card" }, + ], + }), + ); + const panel = mountHtml( + await renderComponent(source, { + title: "", + alertTitle: "Attention", + alertDescription: "Review this state.", + empty: true, + scrollable: true, + maxHeight: "12rem", + }), + ); + + expect(overlay.querySelector(".wire-next__card-overlay")).not.toBeNull(); + expect(group.querySelectorAll(".wire-next__card-group > article")).toHaveLength(2); + expect(panel.querySelector(".wire-next__card-alert")?.getAttribute("role")).toBe("status"); + expect(panel.querySelector(".wire-next__card-empty")?.textContent).toContain("No data to show"); + expect(panel.querySelector(".wire-next__card-body")?.getAttribute("data-scrollable")).toBe( + "true", + ); + + const css = uiCss(); + expect(css).toContain('.wire-next--card[data-layout="horizontal"]'); + expect(css).toContain('.wire-next--card[data-hover="image"]'); + expect(css).toContain(".wire-next__card-group"); + expect(css).toContain(".wire-next__card-navigation-select"); + expect(css).toContain("aspect-ratio: 16 / 9"); + expect(css).toContain("rgb(2 6 23 / 0.86)"); +}); + +test("chat bubble renders conversations, avatars, metadata, links, and public events", async () => { + const source = readFileSync(uiComponentPath("ChatBubble"), "utf8"); + const events: string[] = []; + const dom = mountHtml( + await renderComponent(source, { + ariaLabel: "Support conversation", + oneSided: true, + showAvatars: true, + showMetadata: true, + items: [ + { + direction: "incoming", + author: "Support", + avatarFallback: "SP", + title: "How can we help?", + text: "Choose a guide.", + bullets: ["Installation", "Components"], + links: [{ label: "Installation guide", href: "/installation" }], + status: "Sent", + timestamp: "10:32", + }, + { + direction: "outgoing", + text: "Please retry.", + status: "Not sent", + statusTone: "danger", + action: "retry", + actionLabel: "Retry", + }, + ], + }), + ); + + const root = dom.querySelector(".wire-next--chat-bubble") as HTMLElement; + for (const [name, label] of [ + ["messageClick", "message"], + ["avatarClick", "avatar"], + ["linkClick", "link"], + ["action", "action"], + ]) { + root.addEventListener(name, () => events.push(label)); + } + expect(root.getAttribute("role")).toBe("log"); + expect(root.getAttribute("aria-label")).toBe("Support conversation"); + expect(root.dataset.oneSided).toBe("true"); + expect(dom.querySelectorAll(".wire-next__chat-message")).toHaveLength(2); + expect(dom.querySelectorAll(".wire-next__chat-content li")).toHaveLength(2); + expect(dom.querySelector(".wire-next__chat-meta[data-tone='danger']")).not.toBeNull(); + expect(uiCss()).toContain("color: var(--wire-color-primary-contrast, #fff)"); + + (dom.querySelector(".wire-next__chat-content") as HTMLElement).click(); + (dom.querySelector(".wire-next__chat-avatar") as HTMLButtonElement).click(); + (dom.querySelector(".wire-next__chat-content a") as HTMLAnchorElement).click(); + (dom.querySelector(".wire-next__chat-meta button") as HTMLButtonElement).click(); + expect(events).toEqual(["message", "avatar", "link", "action"]); +}); + +test("collapse toggles accessible panels and emits open, close, and toggle events", async () => { + const source = readFileSync(uiComponentPath("Collapse"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + ariaLabel: "Product details", + initialOpenIndexes: [0], + items: [ + { + id: "product-details", + label: "Expand", + closeLabel: "Collapse", + title: "Details", + content: "Additional product information.", + }, + ], + }), + ); + const root = dom.querySelector(".wire-next--collapse") as HTMLElement; + const trigger = dom.querySelector(".wire-next__collapse-trigger") as HTMLButtonElement; + const panel = dom.querySelector(".wire-next__collapse-panel") as HTMLElement; + const events: string[] = []; + for (const name of ["open", "close", "toggle"]) { + root.addEventListener(name, () => events.push(name)); + } + + expect(root.getAttribute("aria-label")).toBe("Product details"); + expect(trigger.getAttribute("aria-expanded")).toBe("true"); + expect(trigger.getAttribute("aria-controls")).toBe("product-details"); + expect(panel.dataset.open).toBe("true"); + expect(panel.getAttribute("aria-hidden")).toBe("false"); + expect(uiCss()).toContain("max-height: 40rem"); + expect(trigger.textContent).toContain("Collapse"); + + trigger.click(); + expect(trigger.getAttribute("aria-expanded")).toBe("false"); + expect(panel.dataset.open).toBe("false"); + expect(panel.getAttribute("aria-hidden")).toBe("true"); + expect(events).toEqual(["close", "toggle"]); + + trigger.click(); + expect(panel.dataset.open).toBe("true"); + expect(events).toEqual(["close", "toggle", "open", "toggle"]); +}); + +test("collapse supports inline read-more and single or multiple open panels", async () => { + const source = readFileSync(uiComponentPath("Collapse"), "utf8"); + const items = [ + { id: "first-collapse", label: "Read more", preview: "First preview", content: "First" }, + { id: "second-collapse", label: "Read more", preview: "Second preview", content: "Second" }, + ]; + const single = mountHtml(await renderComponent(source, { mode: "inline", items })); + const singleTriggers = single.querySelectorAll( + ".wire-next__collapse-trigger", + ) as HTMLButtonElement[]; + singleTriggers[0]?.click(); + singleTriggers[1]?.click(); + expect(singleTriggers[0]?.getAttribute("aria-expanded")).toBe("false"); + expect(singleTriggers[1]?.getAttribute("aria-expanded")).toBe("true"); + expect(single.querySelectorAll(".wire-next__collapse-preview")).toHaveLength(2); + + const multiple = mountHtml(await renderComponent(source, { multiple: true, items })); + const multipleTriggers = multiple.querySelectorAll( + ".wire-next__collapse-trigger", + ) as HTMLButtonElement[]; + multipleTriggers[0]?.click(); + multipleTriggers[1]?.click(); + expect(multipleTriggers[0]?.getAttribute("aria-expanded")).toBe("true"); + expect(multipleTriggers[1]?.getAttribute("aria-expanded")).toBe("true"); +}); + +test("basic form fields expose shared labels, variants, states, hints, values, and validation targets", async () => { + const { checkField } = await import("../../validation/src/index.ts"); + const validation = checkField( + { + type: "string", + optional: false, + trim: true, + rules: [{ kind: "email", message: "Enter a valid email address." }], + }, + "not-an-email", + ); + expect(validation.error).toBe("Enter a valid email address."); + + const source = readFileSync(uiComponentPath("Input"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "account-email", + name: "email", + label: "Email address", + placeholder: "you@example.com", + value: "not-an-email", + type: "email", + variant: "floating", + icon: "icon-[lucide--mail]", + iconPosition: "end", + helperText: "Used for account notices.", + cornerHint: "Required", + error: validation.error, + inline: true, + required: true, + }), + ); + const root = dom.querySelector(".wire-next--input") as HTMLElement; + const input = dom.querySelector("input") as HTMLInputElement; + expect(root.dataset.variant).toBe("floating"); + expect(root.dataset.inline).toBe("true"); + expect(root.dataset.invalid).toBe("true"); + expect(input.id).toBe("account-email"); + expect(input.name).toBe("email"); + expect(input.value).toBe("not-an-email"); + expect(input.getAttribute("aria-invalid")).toBe("true"); + expect(dom.querySelector("[data-error='email']")?.textContent).toContain( + "Enter a valid email address.", + ); + expect(dom.querySelector(".wire-next__field-hint")?.textContent).toContain("Required"); + expect(dom.querySelector(".wire-next__field-icon")).not.toBeNull(); + + const emitted: string[] = []; + for (const name of ["input", "change", "focus", "blur", "keydown", "keyup"]) { + root.addEventListener(name, () => emitted.push(name)); + } + input.dispatchEvent(new (dom.window as any).Event("input", { bubbles: true })); + input.dispatchEvent(new (dom.window as any).Event("change", { bubbles: true })); + input.dispatchEvent(new (dom.window as any).Event("focus", { bubbles: true })); + input.dispatchEvent(new (dom.window as any).Event("blur", { bubbles: true })); + input.dispatchEvent( + new (dom.window as any).KeyboardEvent("keydown", { key: "Enter", bubbles: true }), + ); + input.dispatchEvent( + new (dom.window as any).KeyboardEvent("keyup", { key: "Enter", bubbles: true }), + ); + expect(emitted).toEqual(["input", "change", "focus", "blur", "keydown", "keyup"]); +}); + +test("all basic form components render values and their must-have interaction events", async () => { + const components = [ + "Checkbox", + "ColorPicker", + "FileInput", + "Input", + "InputGroup", + "Radio", + "RangeSlider", + "Select", + "Switch", + "Textarea", + "TimePicker", + ]; + for (const component of components) { + const source = readFileSync(uiComponentPath(component), "utf8"); + const props: Record = { + id: `${component}-field`, + name: `${component}Value`, + label: `${component} label`, + helperText: "Helper text", + cornerHint: "Optional", + error: "", + inline: true, + readonly: true, + disabled: false, + value: component === "RangeSlider" ? 40 : "value", + options: [{ label: "Value", value: "value" }], + }; + const dom = mountHtml(await renderComponent(source, props)); + const control = dom.querySelector("input, textarea, select") as HTMLElement | null; + expect(control).not.toBeNull(); + expect(control?.getAttribute("name")).toBe(`${component}Value`); + expect(dom.querySelector(".wire-next__field-help")?.textContent).toContain("Helper text"); + expect(dom.querySelector(`[data-error="${component}Value"]`)).not.toBeNull(); + } +}); + +test("radio renders passed options in group, card, list, alignment, and description layouts", async () => { + const source = readFileSync(uiComponentPath("Radio"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "plan", + name: "plan", + label: "Choose a plan", + value: "professional", + orientation: "horizontal", + card: true, + list: true, + rightAligned: true, + options: [ + { label: "Starter", value: "starter", description: "For individuals." }, + { label: "Professional", value: "professional", description: "For teams." }, + { label: "Enterprise", value: "enterprise", disabled: true }, + ], + }), + ); + + const root = dom.querySelector(".wire-next--radio-field") as HTMLElement; + const controls = [...dom.querySelectorAll('input[type="radio"]')] as HTMLInputElement[]; + expect(root.dataset.orientation).toBe("horizontal"); + expect(root.dataset.card).toBe("true"); + expect(root.dataset.list).toBe("true"); + expect(root.dataset.rightAligned).toBe("true"); + expect(controls).toHaveLength(3); + expect(controls[1]?.checked).toBe(true); + expect(controls[2]?.disabled).toBe(true); + expect(dom.querySelectorAll(".wire-next__choice-copy small")).toHaveLength(2); +}); + +test("checkbox renders passed values in group, card, list, alignment, description, and mixed layouts", async () => { + const source = readFileSync(uiComponentPath("Checkbox"), "utf8"); + const group = mountHtml( + await renderComponent(source, { + id: "notifications", + name: "notifications", + label: "Notification preferences", + values: ["account"], + orientation: "horizontal", + card: true, + list: true, + rightAligned: true, + options: [ + { label: "Product", value: "product", description: "Product news." }, + { label: "Account", value: "account", description: "Security alerts." }, + { label: "Partners", value: "partners", disabled: true }, + ], + }), + ); + const controls = [...group.querySelectorAll('input[type="checkbox"]')] as HTMLInputElement[]; + expect(group.querySelector(".wire-next--checkbox-field")?.getAttribute("data-orientation")).toBe( + "horizontal", + ); + expect(controls).toHaveLength(3); + expect(controls[1]?.checked).toBe(true); + expect(controls[2]?.disabled).toBe(true); + expect(group.querySelectorAll(".wire-next__choice-copy small")).toHaveLength(2); + + const mixed = mountHtml( + await renderComponent(source, { id: "mixed", name: "mixed", indeterminate: true }), + ); + expect(mixed.querySelector("input")?.getAttribute("aria-checked")).toBe("mixed"); +}); + +test("range slider exposes value, minimum, maximum, step, bounds, and optional marks", async () => { + const source = readFileSync(uiComponentPath("RangeSlider"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "volume", + name: "volume", + value: 50, + min: 0, + max: 100, + step: 25, + showBounds: true, + showSteps: true, + marks: [ + { value: 0, label: "Minimum" }, + { value: 50, label: "Middle" }, + { value: 100, label: "Maximum" }, + ], + }), + ); + + const control = dom.querySelector('input[type="number"]') as HTMLInputElement; + const slider = dom.querySelector('[role="slider"]') as HTMLElement; + expect(control.min).toBe("0"); + expect(control.max).toBe("100"); + expect(control.step).toBe("25"); + expect(slider.getAttribute("aria-valuenow")).toBe("50"); + expect(dom.querySelector(".wire-next__range-bounds")?.textContent).toContain("Step 25"); + expect(dom.querySelectorAll(".wire-next__slider-marks button")).toHaveLength(3); + expect(slider.getAttribute("tabindex")).toBe("0"); + expect(source).toContain('sourceEvent.key === "ArrowRight"'); + const increase = dom.querySelector('[aria-label="Increase Range"]') as HTMLButtonElement; + increase.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector('[role="slider"]')?.getAttribute("aria-valuenow")).toBe("75"); + dom + .querySelector('[role="slider"]') + ?.dispatchEvent( + new (dom.window as any).KeyboardEvent("keydown", { key: "ArrowRight", bubbles: true }), + ); + expect(dom.querySelector('[role="slider"]')?.getAttribute("aria-valuenow")).toBe("100"); + const middleMark = dom.querySelectorAll( + ".wire-next__slider-marks button", + )[1] as HTMLButtonElement; + middleMark.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector('[role="slider"]')?.getAttribute("aria-valuenow")).toBe("50"); + expect((dom.querySelector('input[type="number"]') as HTMLInputElement).value).toBe("50"); +}); + +test("date picker renders a custom calendar trigger with accessible field state and events", async () => { + const source = readFileSync(uiComponentPath("DatePicker"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "start-date", + name: "startDate", + label: "Start date", + value: "2026-07-28", + min: "2026-01-01", + max: "2026-12-31", + helperText: "Use your local date.", + cornerHint: "Required", + required: true, + }), + ); + const input = dom.querySelector("input") as HTMLInputElement; + expect(input.type).toBe("text"); + expect(input.required).toBe(true); + expect(dom.querySelector("label")?.getAttribute("for")).toBe("start-date"); + expect(dom.querySelector('button[aria-haspopup="dialog"]')).not.toBeNull(); + expect(source).not.toContain('type="{type}"'); + expect(source).toContain("months ="); + expect(dom.querySelector(".wire-next__field-help")?.textContent).toContain("local date"); + const trigger = dom.querySelector('button[aria-haspopup="dialog"]') as HTMLButtonElement; + expect(dom.querySelector(".wire-next--date-picker")?.getAttribute("data-expanded")).toBe("false"); + trigger.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector(".wire-next--date-picker")?.getAttribute("data-expanded")).toBe("true"); + expect(dom.querySelector('button[aria-haspopup="dialog"]')?.getAttribute("aria-expanded")).toBe( + "true", + ); + expect(dom.querySelectorAll(".wire-next__calendar-grid button")).toHaveLength(31); + const fifteenth = dom.querySelectorAll( + ".wire-next__calendar-grid button", + )[14] as HTMLButtonElement; + fifteenth.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(input.value).toBe("2026-07-15"); + expect(dom.querySelector(".wire-next__date-trigger span")?.textContent).toBe("2026-07-15"); +}); + +test("time picker uses a custom reactive panel instead of the browser time control", async () => { + const source = readFileSync(uiComponentPath("TimePicker"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + id: "meeting-time", + name: "meetingTime", + value: "13:30", + format: "12", + minuteStep: 15, + }), + ); + expect(source).not.toContain('type="time"'); + const trigger = dom.querySelector(".wire-next__time-trigger") as HTMLButtonElement; + expect(trigger.textContent).toContain("13:30"); + trigger.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector(".wire-next--time-picker")?.getAttribute("data-expanded")).toBe("true"); + expect(dom.querySelectorAll(".wire-next__time-options").length).toBe(2); + expect(dom.querySelectorAll(".wire-next__time-options button")).toHaveLength(36); + const nine = [...dom.querySelectorAll(".wire-next__time-options button")].find( + (button) => button.textContent?.trim() === "09", + ) as HTMLButtonElement; + nine.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect((dom.querySelector('input[name="meetingTime"]') as HTMLInputElement).value).toBe("09:30"); + expect(dom.querySelector(".wire-next__time-trigger span")?.textContent).toBe("09:30"); +}); + +test("file upload progress reacts to cancel, retry, and complete actions", async () => { + const source = readFileSync(uiComponentPath("FileUploadProgress"), "utf8"); + const dom = mountHtml( + await renderComponent(source, { + fileName: "design-system.zip", + fileSize: "20 MB", + uploadedSize: "10 MB", + value: 50, + max: 100, + status: "uploading", + }), + ); + expect(dom.querySelector(".wire-next--file-upload-progress")?.getAttribute("data-status")).toBe( + "uploading", + ); + expect(dom.querySelector(".wire-next__row")?.textContent).toContain("design-system.zip"); + const buttons = dom.querySelectorAll(".wire-next__upload-actions button") as HTMLButtonElement[]; + buttons[0]?.dispatchEvent(new (dom.window as any).Event("click", { bubbles: true })); + expect(dom.querySelector(".wire-next--file-upload-progress")?.getAttribute("data-status")).toBe( + "cancelled", + ); +}); + +test("carousel renders accessible slides, pagination, counter, and navigation events", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const html = await renderComponent(source, { + ariaLabel: "Featured stories", + showPagination: true, + showCounter: true, + items: [ + { title: "First story", description: "First description" }, + { title: "Second story", description: "Second description" }, + { title: "Third story", description: "Third description" }, + ], + }); + const dom = mountHtml(html); + const carousel = dom.querySelector(".wire-next--carousel") as HTMLElement; + const scopeRoot = dom.querySelector("[data-wrn-scope]") as HTMLElement; + const encodedScope = scopeRoot.getAttribute("data-wrn-scope") ?? ""; + const hydratedScope = JSON.parse(Buffer.from(encodedScope, "base64").toString("utf8")) as { + items: Array<{ title: string }>; + }; + const events: string[] = []; + for (const name of ["change", "next", "previous"]) { + carousel.addEventListener(name, () => events.push(name)); + } + + expect(carousel.getAttribute("role")).toBe("region"); + expect(carousel.getAttribute("aria-roledescription")).toBe("carousel"); + expect(carousel.getAttribute("aria-label")).toBe("Featured stories"); + expect(hydratedScope.items.map((item) => item.title)).toEqual([ + "First story", + "Second story", + "Third story", + ]); + expect(dom.querySelectorAll('[aria-roledescription="slide"]')).toHaveLength(3); + expect(dom.querySelectorAll(".wire-next__carousel-pagination button")).toHaveLength(3); + expect(dom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("1 / 3"); + + (dom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement).click(); + expect(dom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("2 / 3"); + expect(events).toEqual(["change", "next"]); + + (dom.querySelector('[aria-label="Previous slide"]') as HTMLButtonElement).click(); + expect(events).toEqual(["change", "next", "change", "previous"]); +}); + +test("carousel supports RTL, multiple slides, dragging, snap, and thumbnail layouts", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const items = [{ title: "First" }, { title: "Second" }, { title: "Third" }, { title: "Fourth" }]; + const html = await renderComponent(source, { + items, + slidesPerView: 3, + isRTL: true, + isDraggable: true, + isAutoHeight: true, + thumbnails: "vertical", + }); + const dom = mountHtml(html); + const carousel = dom.querySelector(".wire-next--carousel") as HTMLElement; + const track = dom.querySelector(".wire-next__carousel-track") as HTMLElement; + + expect(carousel.getAttribute("dir")).toBe("rtl"); + expect(carousel.dataset.draggable).toBe("true"); + expect(carousel.dataset.autoHeight).toBe("true"); + expect(carousel.dataset.thumbnails).toBe("vertical"); + expect(track.getAttribute("style")).toContain("--wire-carousel-per-view: 3"); + expect(dom.querySelectorAll(".wire-next__carousel-thumbnails button")).toHaveLength(4); + + const snapHtml = await renderComponent(source, { + items, + isSnap: true, + isDraggable: true, + }); + const snapDom = mountHtml(snapHtml); + const snapRoot = snapDom.querySelector(".wire-next--carousel") as HTMLElement; + expect(snapRoot.dataset.snap).toBe("true"); + expect(snapRoot.dataset.draggable).toBe("false"); + + const css = uiCss(); + expect(css).toContain('.wire-next--carousel[data-rtl="true"]'); + expect(css).toContain('.wire-next--carousel[data-snap="true"]'); + expect(css).toContain('.wire-next--carousel[data-thumbnails="vertical"]'); + expect(css).toContain("user-select: none"); + expect(css).toContain('.wire-next--carousel[data-centered="true"] .wire-next__carousel-track'); +}); + +test("carousel autoplay timers are available in the browser reactive runtime", async () => { + const { getReactiveRuntime } = await import("../../csr/src/index.ts"); + const runtime = getReactiveRuntime(); + expect(runtime).toContain('name === "setInterval"'); + expect(runtime).toContain('name === "clearInterval"'); +}); + +test("carousel snap controls scroll and multiple slides stop at the last full group", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const items = [ + { title: "First" }, + { title: "Second" }, + { title: "Third" }, + { title: "Fourth" }, + { title: "Fifth" }, + { title: "Sixth" }, + ]; + const snapDom = mountHtml( + await renderComponent(source, { + items, + isSnap: true, + showPagination: true, + }), + ); + const viewport = snapDom.querySelector(".wire-next__carousel-viewport") as HTMLElement & { + scrollTo: (options: ScrollToOptions) => void; + }; + let scrollLeft: number | undefined; + viewport.scrollTo = (options: ScrollToOptions | number) => { + scrollLeft = typeof options === "number" ? options : options.left; + }; + ( + snapDom.querySelectorAll(".wire-next__carousel-pagination button")[1] as HTMLButtonElement + ).click(); + expect(scrollLeft).toBeDefined(); + const snapNext = snapDom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement; + for (let index = 0; index < items.length; index++) snapNext.click(); + const paginationButtons = snapDom.querySelectorAll(".wire-next__carousel-pagination button"); + expect(paginationButtons[items.length - 1]?.getAttribute("aria-current")).toBe("true"); + expect(snapNext.disabled).toBe(true); + + const multipleDom = mountHtml( + await renderComponent(source, { + items, + slidesPerView: 3, + showCounter: true, + }), + ); + const next = multipleDom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement; + for (let index = 0; index < 6; index++) next.click(); + expect(multipleDom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("4 / 6"); + expect(next.disabled).toBe(true); +}); + +test("carousel centers the last slide and auto-scrolls thumbnail rails", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const items = [{ title: "First" }, { title: "Second" }, { title: "Third" }, { title: "Fourth" }]; + const centeredDom = mountHtml( + await renderComponent(source, { + items, + isCentered: true, + showCounter: true, + }), + ); + const centeredNext = centeredDom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement; + for (let index = 0; index < items.length; index++) centeredNext.click(); + expect(centeredDom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("4 / 4"); + expect(centeredNext.disabled).toBe(true); + + for (const thumbnails of ["horizontal", "vertical"]) { + const dom = mountHtml(await renderComponent(source, { items, thumbnails })); + const buttons = dom.querySelectorAll( + ".wire-next__carousel-thumbnails button", + ) as HTMLButtonElement[]; + let scrolled = false; + const rail = buttons[1]?.parentElement as HTMLElement & { + scrollTo: (options: ScrollToOptions) => void; + }; + rail.scrollTo = () => { + scrolled = true; + }; + (dom.querySelector('[aria-label="Next slide"]') as HTMLButtonElement).click(); + expect(scrolled).toBe(true); + } +}); + +test("carousel autoplay wraps to the first slide", async () => { + const source = readFileSync(uiComponentPath("Carousel"), "utf8"); + const html = await renderComponent(source, { + isAutoPlay: true, + autoplayInterval: 1000, + activeIndex: 2, + showCounter: true, + items: [{ title: "First" }, { title: "Second" }, { title: "Third" }], + }); + const dom = mountHtml(html); + await Bun.sleep(1100); + expect(dom.querySelector(".wire-next__carousel-counter")?.textContent).toContain("1 / 3"); + dom + .querySelector(".wire-next--carousel") + ?.dispatchEvent(new (dom.window as any).Event("mouseenter", { bubbles: true })); +}); + +test("input number increments, decrements, applies steps, and respects limits", async () => { + const source = readFileSync(uiComponentPath("InputNumber"), "utf8"); + const html = await renderComponent(source, { + name: "quantity", + value: 1, + min: 0, + max: 5, + step: 2, + }); + const dom = mountHtml(html); + const input = () => dom.querySelector('input[name="quantity"]') as HTMLInputElement; + const decrement = () => dom.querySelector('[aria-label="Decrease value"]') as HTMLButtonElement; + const increment = () => dom.querySelector('[aria-label="Increase value"]') as HTMLButtonElement; + + expect(input().value).toBe("1"); + + increment().click(); + expect(input().value).toBe("3"); + + increment().click(); + expect(input().value).toBe("5"); + expect(increment().disabled).toBe(true); + + decrement().click(); + expect(input().value).toBe("3"); + + decrement().click(); + decrement().click(); + expect(input().value).toBe("0"); + expect(decrement().disabled).toBe(true); +}); + +test("advanced select opens, filters, and selects without reactive handler errors", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const html = await renderComponent(source, { + name: "team", + options: [ + { value: "design", label: "Design" }, + { value: "engineering", label: "Engineering" }, + { value: "growth", label: "Growth" }, + ], + }); + const dom = mountHtml(html); + const trigger = dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement; + expect(trigger).not.toBeNull(); + trigger.click(); + expect( + dom.querySelector(".wire-next--advanced-select")?.classList.contains("wire-next--open"), + ).toBe(true); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("true"); + expect(dom.querySelector('[role="listbox"]')).not.toBeNull(); + const search = dom.querySelector(".wire-next__select-search input") as HTMLInputElement; + search.value = "engine"; + search.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + const options = dom.querySelectorAll(".wire-next__select-option") as HTMLButtonElement[]; + expect(options.filter((option) => option.style.display !== "none")).toHaveLength(1); + options.find((option) => option.style.display !== "none")?.click(); + expect(dom.querySelector(".wire-next__select-value > span")?.textContent).toBe("Engineering"); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("false"); + (dom.querySelector(".wire-next__clear-select") as HTMLButtonElement).click(); + expect(dom.querySelector(".wire-next__select-value > span")?.textContent).toBe( + "Select an option", + ); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe(""); +}); + +test("advanced select clears, restores its placeholder, and keeps multiple counters accurate", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const html = await renderComponent(source, { + name: "team", + multiple: true, + values: ["design", "engineering"], + showCounter: true, + maxSelections: 3, + placeholder: "Choose teams", + options: [ + { value: "design", label: "Design" }, + { value: "engineering", label: "Engineering" }, + { value: "growth", label: "Growth" }, + ], + }); + const dom = mountHtml(html); + const trigger = dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement; + const counter = dom.querySelector(".wire-next__row small"); + expect(counter?.textContent).toBe("2 / 3 selected"); + + trigger.click(); + const buttons = dom.querySelectorAll(".wire-next__select-option") as HTMLButtonElement[]; + const scope = dom.querySelector("[data-wrn-select]") as HTMLElement & { + __wrnexusScopeApi?: { + get(name: string): unknown; + call(name: string, value?: unknown): unknown; + }; + }; + expect(scope.__wrnexusScopeApi?.get("maxSelections")).toBe(3); + expect(scope.__wrnexusScopeApi?.call("selectedCount")).toBe(2); + expect(scope.__wrnexusScopeApi?.call("canSelect", { value: "growth", label: "Growth" })).toBe( + true, + ); + expect(buttons.find((button) => button.textContent?.includes("Growth"))?.disabled).toBe(false); + buttons.find((button) => button.textContent?.includes("Engineering"))?.click(); + expect(counter?.textContent).toBe("1 / 3 selected"); + buttons.find((button) => button.textContent?.includes("Design"))?.click(); + expect(counter?.textContent).toBe("0 / 3 selected"); + expect( + dom.querySelector(".wire-next__placeholder")?.parentElement?.getAttribute("data-show"), + ).toBe("true"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe(""); +}); + +test("advanced select closes when a pointer event occurs outside it", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const html = await renderComponent(source, { + name: "team", + options: [{ value: "design", label: "Design" }], + }); + const dom = mountHtml(html); + (dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement).click(); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("true"); + dom.document.body.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("pointerdown", { bubbles: true }), + ); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("false"); +}); + +test("advanced select fetches remote options and appends infinite pages", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const originalFetch = globalThis.fetch; + const requests: string[] = []; + globalThis.fetch = (async (input: string | URL | Request) => { + const url = String(input); + requests.push(url); + const parsedUrl = new URL(url); + const page = parsedUrl.searchParams.get("page"); + const query = parsedUrl.searchParams.get("q"); + return Response.json( + page === "1" + ? { + items: query + ? [{ value: "engineering", label: "Engineering" }] + : [{ value: "design", label: "Design" }], + hasMore: true, + } + : { items: [{ value: "support", label: "Support" }], hasMore: false }, + ); + }) as unknown as typeof fetch; + + try { + const html = await renderComponent(source, { + name: "team", + options: [], + remote: true, + remoteUrl: "https://example.test/api/teams", + infinite: true, + hasMore: true, + remoteDebounce: 0, + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-select]") as HTMLElement & { + __wrnexusSelectController?: { attempts: number }; + __wrnexusScopeApi?: { get(name: string): unknown }; + }; + expect(root.getAttribute("data-remote")).toBe("true"); + expect(root.getAttribute("data-remote-url")).toBe("https://example.test/api/teams"); + expect(root.getAttribute("data-remote-auto-load")).toBe("true"); + expect(root.__wrnexusSelectController).toBeDefined(); + expect(root.__wrnexusScopeApi).toBeDefined(); + expect(root.__wrnexusScopeApi?.get("minSearchLength")).toBe(0); + expect(root.__wrnexusSelectController?.attempts).toBe(1); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(requests).toHaveLength(1); + expect( + dom.querySelectorAll(".wire-next__select-option").map((node) => node.textContent), + ).toEqual(["Design"]); + (dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement).click(); + (dom.querySelector(".wire-next__select-option") as HTMLButtonElement).click(); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe("design"); + expect(dom.querySelector(".wire-next__select-value > span")?.textContent).toBe("Design"); + + const search = dom.querySelector(".wire-next__select-search input") as HTMLInputElement; + search.value = "engine"; + search.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(requests.at(-1)).toContain("q=engine"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe("design"); + expect(dom.querySelector(".wire-next__select-value > span")?.textContent).toBe("Design"); + + (dom.querySelector("[data-wrn-select-load-more]") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect( + dom.querySelectorAll(".wire-next__select-option").map((node) => node.textContent), + ).toEqual(["Engineering", "Support"]); + expect(requests).toHaveLength(3); + expect(requests[2]).toContain("page=2"); + } finally { + globalThis.fetch = originalFetch; + } +}); + +test("combobox filters editable input, selects suggestions, exposes methods, and clears", async () => { + const source = readFileSync(uiComponentPath("ComboBox"), "utf8"); + const html = await renderComponent(source, { + name: "team", + placeholder: "Search teams", + options: [ + { value: "design", label: "Design", description: "Product design" }, + { value: "engineering", label: "Engineering", description: "Platform engineering" }, + { value: "growth", label: "Growth", description: "Customer growth" }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-combobox]") as HTMLElement & { + wrnexusCombobox?: { + open(): void; + close(): void; + clear(): void; + setValue(value: string): void; + }; + }; + const input = dom.querySelector(".wire-next__combobox-input") as HTMLInputElement; + const hidden = dom.querySelector('input[type="hidden"]') as HTMLInputElement; + + expect(root.wrnexusCombobox).toBeDefined(); + input.focus(); + input.value = "engi"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect( + dom + .querySelectorAll(".wire-next__select-option") + .filter((option) => (option as HTMLElement).style.display !== "none") + .map((option) => option.textContent?.trim()), + ).toEqual(["EngineeringPlatform engineering"]); + + input.value = "No matching team"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("false"); + expect(input.value).toBe("No matching team"); + + input.value = "engi"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + input.dispatchEvent( + new (dom.window as { KeyboardEvent: typeof KeyboardEvent }).KeyboardEvent("keydown", { + key: "Enter", + bubbles: true, + }), + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(input.value).toBe("Engineering"); + expect(hidden.value).toBe("engineering"); + expect(dom.querySelector(".wire-next__select-dropdown")?.getAttribute("data-show")).toBe("false"); + + root.wrnexusCombobox?.clear(); + expect(input.value).toBe(""); + expect(hidden.value).toBe(""); + root.wrnexusCombobox?.setValue("growth"); + expect(input.value).toBe("Growth"); + expect(hidden.value).toBe("growth"); +}); + +test("combobox auto-loads remote suggestions and retains its selected value while searching", async () => { + const source = readFileSync(uiComponentPath("ComboBox"), "utf8"); + const originalFetch = globalThis.fetch; + const requests: string[] = []; + globalThis.fetch = (async (input: string | URL | Request) => { + const url = new URL(String(input)); + requests.push(url.toString()); + const query = url.searchParams.get("q"); + return Response.json({ + items: query + ? [{ value: "engineering", label: "Engineering" }] + : [{ value: "design", label: "Design" }], + hasMore: false, + }); + }) as typeof fetch; + + try { + const html = await renderComponent(source, { + name: "remote-team", + remote: true, + remoteUrl: "https://example.test/api/teams", + remoteDebounce: 0, + }); + const dom = mountHtml(html); + const input = dom.querySelector(".wire-next__combobox-input") as HTMLInputElement; + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(requests).toHaveLength(1); + + input.focus(); + (dom.querySelector(".wire-next__select-option") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(input.value).toBe("Design"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe("design"); + + input.value = "engine"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(requests.at(-1)).toContain("q=engine"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe(""); + (dom.querySelector(".wire-next__select-option") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(input.value).toBe("Engineering"); + expect((dom.querySelector('input[type="hidden"]') as HTMLInputElement).value).toBe( + "engineering", + ); + } finally { + globalThis.fetch = originalFetch; + } +}); + +test("combobox emits search, select, change, clear, open, and close events", async () => { + const source = readFileSync(uiComponentPath("ComboBox"), "utf8"); + const html = await renderComponent(source, { + name: "events-team", + options: [ + { value: "design", label: "Design" }, + { value: "engineering", label: "Engineering" }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-combobox]") as HTMLElement; + const input = dom.querySelector(".wire-next__combobox-input") as HTMLInputElement; + const received: Array<{ name: string; detail: Record }> = []; + for (const name of ["search", "select", "change", "clear", "open", "close"]) { + root.addEventListener(`wrnexus:${name}`, ((event: CustomEvent) => { + received.push({ name, detail: event.detail }); + }) as EventListener); + } + + input.focus(); + await new Promise((resolve) => setTimeout(resolve, 0)); + input.value = "engi"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + input.dispatchEvent( + new (dom.window as { KeyboardEvent: typeof KeyboardEvent }).KeyboardEvent("keydown", { + key: "Enter", + bubbles: true, + }), + ); + await new Promise((resolve) => setTimeout(resolve, 0)); + (dom.querySelector(".wire-next__clear-select") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + + expect(received.map((event) => event.name)).toEqual( + expect.arrayContaining(["search", "select", "change", "clear", "open", "close"]), + ); + expect(received.find((event) => event.name === "search")?.detail).toEqual( + expect.objectContaining({ component: "ComboBox", query: "engi" }), + ); + expect(received.find((event) => event.name === "select")?.detail).toEqual( + expect.objectContaining({ value: "engineering" }), + ); +}); + +test("advanced select emits selection events and remote load and error events", async () => { + const source = readFileSync(uiComponentPath("AdvancedSelect"), "utf8"); + const originalFetch = globalThis.fetch; + const originalConsoleError = console.error; + let rejectRequest = false; + globalThis.fetch = (async () => { + if (rejectRequest) throw new Error("Remote unavailable"); + return Response.json({ + items: [{ value: "design", label: "Design" }], + hasMore: false, + }); + }) as unknown as typeof fetch; + console.error = () => {}; + + try { + const html = await renderComponent(source, { + name: "advanced-events", + options: [], + remote: true, + remoteUrl: "https://example.test/api/teams", + remoteAutoLoad: true, + remoteDebounce: 0, + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-select]") as HTMLElement & { + __wrnexusSelectController?: { load(append: boolean, allowEmptyQuery?: boolean): void }; + }; + const received: Array<{ name: string; detail: Record }> = []; + for (const name of ["load", "error", "select", "change", "clear"]) { + root.addEventListener(`wrnexus:${name}`, ((event: CustomEvent) => { + received.push({ name, detail: event.detail }); + }) as EventListener); + } + + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + (dom.querySelector(".wire-next__select-trigger") as HTMLButtonElement).click(); + (dom.querySelector(".wire-next__select-option") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + (dom.querySelector(".wire-next__clear-select") as HTMLButtonElement).click(); + await new Promise((resolve) => setTimeout(resolve, 0)); + + rejectRequest = true; + root.__wrnexusSelectController?.load(false, true); + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); + + expect(received.map((event) => event.name)).toEqual( + expect.arrayContaining(["load", "select", "change", "clear", "error"]), + ); + expect(received.find((event) => event.name === "load")?.detail).toEqual( + expect.objectContaining({ + component: "AdvancedSelect", + page: 1, + hasMore: false, + }), + ); + expect(received.find((event) => event.name === "error")?.detail).toEqual( + expect.objectContaining({ + component: "AdvancedSelect", + message: "Remote unavailable", + }), + ); + } finally { + globalThis.fetch = originalFetch; + console.error = originalConsoleError; + } +}); + +test("pin input accepts matching characters, advances focus, navigates backward, and completes", async () => { + const source = readFileSync(uiComponentPath("PinInput"), "utf8"); + const html = await renderComponent(source, { + name: "verificationCode", + length: 4, + pattern: "[0-9]", + value: "", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-pin-input]") as HTMLElement & { + wrnexusPinInput?: { + focus(index?: number): void; + clear(): void; + setValue(value: string): void; + getValue(): string; + }; + }; + const cells = dom.querySelectorAll("[data-pin-cell]") as HTMLInputElement[]; + const hidden = dom.querySelector("[data-pin-value]") as HTMLInputElement; + const events: string[] = []; + const publicEvents: string[] = []; + for (const name of ["input", "change", "complete", "clear"]) { + root.addEventListener(`wrnexus:${name}`, () => events.push(name)); + root.addEventListener(name, () => publicEvents.push(name)); + } + + expect(cells).toHaveLength(4); + expect(root.wrnexusPinInput).toBeDefined(); + cells[0].focus(); + cells[0].value = "x"; + cells[0].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect(cells[0].value).toBe(""); + expect(hidden.value).toBe(""); + + for (let index = 0; index < 4; index += 1) { + cells[index].value = String(index + 1); + cells[index].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + } + expect(hidden.value).toBe("1234"); + expect(root.getAttribute("data-complete")).toBe("true"); + expect(events).toContain("complete"); + expect(publicEvents).toContain("complete"); + + cells[3].value = ""; + cells[3].dispatchEvent( + new (dom.window as { KeyboardEvent: typeof KeyboardEvent }).KeyboardEvent("keydown", { + key: "Backspace", + bubbles: true, + }), + ); + expect(cells[2].value).toBe(""); + expect(hidden.value).toBe("12"); + + root.wrnexusPinInput?.setValue("9876"); + expect(root.wrnexusPinInput?.getValue()).toBe("9876"); + root.wrnexusPinInput?.clear(); + expect(hidden.value).toBe(""); + expect(events).toContain("clear"); +}); + +test("pin input renders four separate cells when length is omitted", async () => { + const source = readFileSync(uiComponentPath("PinInput"), "utf8"); + const html = await renderComponent(source, { + name: "defaultPin", + }); + const dom = mountHtml(html); + + expect(dom.querySelectorAll("[data-pin-cell]")).toHaveLength(4); +}); + +test("pin input distributes filtered clipboard content and emits paste details", async () => { + const source = readFileSync(uiComponentPath("PinInput"), "utf8"); + const html = await renderComponent(source, { + name: "emailCode", + length: 6, + pattern: "[A-Z0-9]", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-pin-input]") as HTMLElement; + const firstCell = dom.querySelector("[data-pin-cell]") as HTMLInputElement; + let pasteDetail: Record | undefined; + root.addEventListener("wrnexus:paste", ((event: CustomEvent) => { + pasteDetail = event.detail; + }) as EventListener); + + const pasteEvent = new (dom.window as { Event: typeof Event }).Event("paste", { + bubbles: true, + cancelable: true, + }); + Object.defineProperty(pasteEvent, "clipboardData", { + value: { getData: () => "A-1b2 C3" }, + }); + firstCell.dispatchEvent(pasteEvent); + + expect((dom.querySelector("[data-pin-value]") as HTMLInputElement).value).toBe("A1B2C3"); + expect(pasteDetail).toEqual( + expect.objectContaining({ + component: "PinInput", + pasted: "A1B2C3", + value: "A1B2C3", + }), + ); +}); + +test("pin input accepts lowercase alphanumeric entry and normalizes it to the configured pattern", async () => { + const source = readFileSync(uiComponentPath("PinInput"), "utf8"); + const html = await renderComponent(source, { + name: "securityCode", + length: 4, + pattern: "[A-Z0-9]", + inputMode: "text", + }); + const dom = mountHtml(html); + const cells = dom.querySelectorAll("[data-pin-cell]") as HTMLInputElement[]; + + cells[0].value = "a"; + cells[0].dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + + expect(cells[0].value).toBe("A"); + expect((dom.querySelector("[data-pin-value]") as HTMLInputElement).value).toBe("A"); +}); + +test("strong password scores input, supports custom special characters, and opens its popover", async () => { + const source = readFileSync(uiComponentPath("StrongPassword"), "utf8"); + const html = await renderComponent(source, { + name: "newPassword", + presentation: "popover", + specialCharactersSet: "@#", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-strong-password]") as HTMLElement; + const input = dom.querySelector('input[name="newPassword"]') as HTMLInputElement; + const strengthEvents: Array<{ level: string; percent: number }> = []; + root.addEventListener("strength", (event) => { + strengthEvents.push( + (event as unknown as CustomEvent<{ level: string; percent: number }>).detail, + ); + }); + + expect(input.minLength).toBe(8); + expect(root.dataset.strength).toBe("empty"); + + input.value = "Secure#9"; + input.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect((dom.querySelector("[data-wrn-strong-password]") as HTMLElement).dataset.strength).toBe( + "strong", + ); + expect((dom.querySelector("[data-wrn-strong-password]") as HTMLElement).dataset.score).toBe("5"); + expect(strengthEvents.at(-1)).toMatchObject({ level: "strong", percent: 100 }); + + const updatedInput = dom.querySelector('input[name="newPassword"]') as HTMLInputElement; + updatedInput.value = "Secure!9"; + updatedInput.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }), + ); + expect((dom.querySelector("[data-wrn-strong-password]") as HTMLElement).dataset.strength).toBe( + "good", + ); + expect(strengthEvents.at(-1)?.percent).toBe(80); + + const currentInput = dom.querySelector('input[name="newPassword"]') as HTMLInputElement; + currentInput.dispatchEvent( + new (dom.window as { Event: typeof Event }).Event("focus", { bubbles: true }), + ); + expect( + (dom.querySelector(".wire-next__strong-password-popover") as HTMLElement).dataset.open, + ).toBe("true"); +}); + +test("strong password completed requirements use a proper checkmark indicator", () => { + const css = uiCss(); + + expect(css).toContain( + '.wire-next__strong-password-requirements li[data-met="true"] > span::after', + ); + expect(css).toContain("transform: rotate(45deg)"); + expect(css).toContain("border-width: 0 0.1rem 0.1rem 0"); + expect(css).not.toContain( + "linear-gradient(135deg, transparent 42%, var(--wire-color-surface) 42% 52%", + ); +}); + +test("toggle count switches pricing values and emits accessible change details", async () => { + const source = readFileSync(uiComponentPath("ToggleCount"), "utf8"); + const html = await renderComponent(source, { + name: "billing", + value: "monthly", + firstValue: "monthly", + firstLabel: "Monthly", + secondValue: "annual", + secondLabel: "Annual", + animate: false, + items: [ + { label: "Startup", monthly: 19, annual: 190 }, + { label: "Team", monthly: 89, annual: 890 }, + ], + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-toggle-count]") as HTMLElement; + let detail: Record | undefined; + root.addEventListener("toggle", (event) => { + detail = (event as unknown as CustomEvent>).detail; + }); + + expect(root.dataset.value).toBe("monthly"); + expect( + dom + .querySelectorAll(".wire-next__toggle-count-items strong > span") + .map((node) => node.textContent), + ).toEqual(["19", "89"]); + + (dom.querySelector('button[aria-pressed="false"]') as HTMLButtonElement).click(); + + const updatedRoot = dom.querySelector("[data-wrn-toggle-count]") as HTMLElement; + expect(updatedRoot.dataset.value).toBe("annual"); + expect( + dom + .querySelectorAll(".wire-next__toggle-count-items strong > span") + .map((node) => node.textContent), + ).toEqual(["190", "890"]); + expect((dom.querySelector('input[name="billing"]') as HTMLInputElement).value).toBe("annual"); + expect(dom.querySelector('button[aria-pressed="true"]')?.textContent).toBe("Annual"); + expect(detail).toMatchObject({ + component: "ToggleCount", + name: "billing", + value: "annual", + previousValue: "monthly", + }); +}); + +test("toggle count animates every price upward and downward", async () => { + const source = readFileSync(uiComponentPath("ToggleCount"), "utf8"); + const html = await renderComponent(source, { + value: "monthly", + animationDuration: 40, + animationSteps: 4, + items: [ + { label: "Startup", monthly: 2, annual: 10 }, + { label: "Team", monthly: 4, annual: 20 }, + ], + }); + const dom = mountHtml(html); + const values = () => + dom.querySelectorAll("[data-toggle-count-value]").map((node) => Number(node.textContent)); + const button = (label: string) => + dom + .querySelectorAll(".wire-next__toggle-count-segmented button") + .find((node) => node.textContent === label) as HTMLButtonElement; + + button("Annual").click(); + expect(values()).toEqual([2, 4]); + await new Promise((resolve) => setTimeout(resolve, 15)); + expect(values().every((value) => Number.isInteger(value))).toBe(true); + await new Promise((resolve) => setTimeout(resolve, 80)); + expect(values()).toEqual([10, 20]); + + button("Monthly").click(); + expect(values()).toEqual([10, 20]); + await new Promise((resolve) => setTimeout(resolve, 15)); + expect(values().every((value) => Number.isInteger(value))).toBe(true); + await new Promise((resolve) => setTimeout(resolve, 80)); + expect(values()).toEqual([2, 4]); +}); + +test("toggle count switch exposes switch semantics and respects disabled state", async () => { + const source = readFileSync(uiComponentPath("ToggleCount"), "utf8"); + const html = await renderComponent(source, { + variant: "switch", + value: "monthly", + disabled: true, + items: [{ label: "Startup", monthly: 19, annual: 190 }], + }); + const dom = mountHtml(html); + const control = dom.querySelector('[role="switch"]') as HTMLButtonElement; + + expect(control.getAttribute("aria-checked")).toBe("false"); + expect(control.disabled).toBe(true); + control.click(); + expect((dom.querySelector("[data-wrn-toggle-count]") as HTMLElement).dataset.value).toBe( + "monthly", + ); +}); + +test("toggle password reveals and conceals its value with accessible declared events", async () => { + const source = readFileSync(uiComponentPath("TogglePassword"), "utf8"); + const html = await renderComponent(source, { + name: "accountPassword", + value: "correct-horse", + }); + const dom = mountHtml(html); + const root = dom.querySelector("[data-wrn-toggle-password]") as HTMLElement; + const input = dom.querySelector('input[name="accountPassword"]') as HTMLInputElement; + const toggle = dom.querySelector(".wire-next__password-toggle") as HTMLButtonElement; + const showIcon = dom.querySelector(".wire-next__password-icon--show") as HTMLElement; + const visibility: boolean[] = []; + root.addEventListener("toggle", (event) => { + visibility.push((event as unknown as CustomEvent).detail.visible); + }); + + expect(input.type).toBe("password"); + expect(input.pattern).toBe("(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}"); + expect(showIcon).not.toBeNull(); + expect(toggle.getAttribute("aria-pressed")).toBe("false"); + toggle.click(); + expect(input.type).toBe("text"); + expect(input.value).toBe("correct-horse"); + expect(toggle.getAttribute("aria-pressed")).toBe("true"); + expect(visibility).toEqual([true]); + toggle.click(); + expect(input.type).toBe("password"); + expect(visibility).toEqual([true, false]); +}); + +test("toggle password supports checkbox control and synchronized password fields", async () => { + const source = readFileSync(uiComponentPath("TogglePassword"), "utf8"); + const synchronizedHtml = await renderComponent(source, { + name: "credentials", + fields: [ + { + label: "New password", + name: "newPassword", + placeholder: "Enter new password", + autocomplete: "new-password", + }, + { + label: "Current password", + name: "currentPassword", + value: "existing-secret", + autocomplete: "current-password", + pattern: ".{12,}", + }, + ], + }); + const synchronizedDom = mountHtml(synchronizedHtml); + const synchronizedInputs = synchronizedDom.querySelectorAll( + ".wire-next__password-control > input", + ) as HTMLInputElement[]; + const synchronizedToggle = synchronizedDom.querySelector( + ".wire-next__password-toggle", + ) as HTMLButtonElement; + + expect(synchronizedInputs).toHaveLength(2); + expect(synchronizedInputs[0].pattern).toBe( + "(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}", + ); + expect(synchronizedInputs[1].pattern).toBe(".{12,}"); + expect(synchronizedInputs.map((input) => input.type)).toEqual(["password", "password"]); + synchronizedToggle.click(); + expect(synchronizedInputs.map((input) => input.type)).toEqual(["text", "text"]); + + const checkboxHtml = await renderComponent(source, { + name: "checkboxPassword", + toggleMode: "checkbox", + }); + const checkboxDom = mountHtml(checkboxHtml); + const checkbox = checkboxDom.querySelector( + ".wire-next__password-checkbox input", + ) as HTMLInputElement; + const checkboxPassword = checkboxDom.querySelector( + ".wire-next__password-control > input", + ) as HTMLInputElement; + checkbox.checked = true; + checkbox.dispatchEvent( + new (checkboxDom.window as { Event: typeof Event }).Event("change", { bubbles: true }), + ); + + expect(checkboxPassword.type).toBe("text"); +}); diff --git a/AUTH-MANIFEST.md b/AUTH-MANIFEST.md deleted file mode 100644 index 075895d1..00000000 --- a/AUTH-MANIFEST.md +++ /dev/null @@ -1,14 +0,0 @@ -# @wrnexus/auth bundle manifest - -- Package: `packages/auth` -- Version: `0.5.0` -- Components: 16 -- Package API routes: 25 -- Package middleware: auth-session hydration -- Browser runtime: passkey/WebAuthn coordinator -- Stores: memory and generic SQL -- Migration: 13 authentication/security tables -- Showcase: `examples/auth-showcase` -- Root validation: `bun run validate:auth` - -The package includes password, verification, recovery, passwordless OTP, MFA, TOTP, recovery codes, passkeys, OAuth, invitations, sessions, trusted devices, risk/CAPTCHA escalation, account status, impersonation, secret protection, and audit events. diff --git a/AUTH-VALIDATION.md b/AUTH-VALIDATION.md deleted file mode 100644 index f9433349..00000000 --- a/AUTH-VALIDATION.md +++ /dev/null @@ -1,19 +0,0 @@ -# @wrnexus/auth validation report - -Validated in the artifact environment: - -- Strict TypeScript check for package source and tests: passed -- Strict TypeScript check for authentication showcase: passed -- WRN parser check for package components and showcase pages: 27 files passed -- Browser runtime JavaScript syntax check: passed -- Structural package verification: passed -- Compiled engine runtime smoke test: registration, verification, password login, passwordless OTP, invitation, sessions, and impersonation passed -- Compiled security smoke test: encrypted TOTP/OAuth values, TOTP replay rejection, passkey flow, unverified OAuth-link rejection, and CAPTCHA escalation passed - -The full Bun 1.3.14 test/build suite must be run in the WRNexusJS repository with: - -```bash -bun install -bun run validate:auth -bun run check -``` diff --git a/CHANGELOG-0.4.0.md b/CHANGELOG-0.4.0.md deleted file mode 100644 index ef1d81e1..00000000 --- a/CHANGELOG-0.4.0.md +++ /dev/null @@ -1,37 +0,0 @@ -# WRNexusJS 0.4.0 - -## Package platform - -- Added automatic package plugin discovery from application dependencies and workspaces. -- Added package-owned components, client runtimes, assets, styles, routes, middleware, database migrations, and DevToolbar panels. -- Added duplicate/collision validation and strict discovery in development, build, doctor, and inspect flows. -- Added production content-hashed client runtimes, content-addressed package asset storage with stable public URLs, and page-scoped runtime injection. -- Added development bundling for TypeScript package runtimes and package-source HMR. -- Added CSR package runtime mount/unmount lifecycle. - -## CLI and diagnostics - -- Added `wrnexus inspect packages|plugins|routes|assets|runtimes|styles|migrations|bundle`. -- Added `wrnexus generate system `. -- Expanded production build reports with all route types, plugins, runtimes, assets, component directories, and package migrations. -- Added the 0.4 application migration and release verification scripts. -- Fixed duplicate historical migration IDs. - -## CAPTCHA - -- Removed manual `captcha.js` copying and script inclusion. -- Removed duplicated CAPTCHA components from `@wrnexus/ui` and the showcase application. -- CAPTCHA is now discovered from `@wrnexus/captcha` and injected only on pages that render it. -- Preserved all challenge modes, audio, protected-page flow, validated form, compact/normal/big modes, Listen controls, not-robot mode, disturbance controls, and image-style renderers. - -## Existing packages - -Every existing package received an exported advanced capability layer. See `docs/PACKAGE-UPGRADES-0.4.md` for the package-by-package inventory. - -## Fixes - -- Package runtime and asset path collisions now fail before serving. -- Production style processing fails closed by default. -- Page ETags now include structured script metadata. -- Package `.wrn` changes invalidate Tailwind output during HMR. -- Package migrations use the same ordered migration contract as application migrations. diff --git a/INSTALL.md b/INSTALL.md deleted file mode 100644 index 532098e8..00000000 --- a/INSTALL.md +++ /dev/null @@ -1,33 +0,0 @@ -# WRNexusJS auth form and validation fix - -Copy this patch over the WRNexusJS repository root (`E:\WireJS`) and allow matching files to be replaced. - -## What this fixes - -- Auth API files now export HTTP method handlers (`GET` / `POST`) instead of unsupported default-only handlers. -- The package auth dispatcher exports `GET` and `POST`, so package-contributed API routes are callable by the runtime. -- The sign-up form is intercepted by the `@wrnexus/validation` browser runtime instead of navigating the browser directly to the JSON API. -- The same `signUpSchema` validates registration in the browser and in the showcase API route. -- Shared auth HTTP handlers validate core request bodies with `parseBody(...)` from `@wrnexus/validation`. -- Backend field errors and network/API failures are displayed in the form. -- Successful registration redirects to `/sign-in`. -- The in-memory auth showcase disables SQL migration bundling, so its production build does not require `config.db`. - -## Run - -```bash -cd E:/WireJS -bun install -bun run format -bun run check -bun run validate:auth -bun run auth:dev -``` - -Open: - -```text -http://localhost:3000/sign-up -``` - -Do not use `/api/auth/register` as the registration page. It is a POST-only JSON endpoint. Opening it directly with GET should now return a JSON `405 Method Not Allowed` response instead of an invalid server response. diff --git a/MANIFEST-0.4.0.md b/MANIFEST-0.4.0.md deleted file mode 100644 index 266e69cb..00000000 --- a/MANIFEST-0.4.0.md +++ /dev/null @@ -1,109 +0,0 @@ -# WRNexusJS 0.4.0 upgrade manifest - -This replacement upgrades the uploaded WRNexusJS repository to the 0.4.0 platform baseline and preserves existing APIs where practical. - -Compared with the uploaded baseline archive, the final tree contains 45 added files, 214 modified files, and 15 removed obsolete or generated files. - -## Main platform additions - -- Automatic installed/workspace package discovery through `package.json` `wrnexus.plugin` -- Package-owned component directories -- Page-scoped client runtimes -- Virtual development assets with secure content types -- Hashed production runtime assets -- Package CSS entries and Tailwind scan sources -- Package page/API/realtime routes and middleware -- Package database migrations -- Package DevToolbar panels -- Dependency ordering, duplicate detection, cycle detection, and safe contribution validation -- Runtime mount/unmount lifecycle during CSR navigation -- Package-aware HMR and build reporting -- `wrnexus inspect` commands and `wrnexus generate system` -- 0.4 migration and compatibility tooling - -## CAPTCHA integration - -`@wrnexus/captcha` is now self-contained and automatically discovered. The old duplicate copies are removed from `@wrnexus/ui` and the showcase. The package contributes its own component, runtime, Tailwind scan source, and DevToolbar audit. - -Developers use: - -```bash -bun add @wrnexus/captcha -``` - -```wrn - -``` - -They do not copy `captcha.js`, add a script tag, or manually register `captchaPlugin()` for normal use. The runtime is injected only on pages that render a CAPTCHA. - -## Existing packages upgraded - -| Package | 0.4.0 addition or hardening | -| ---------------------- | ------------------------------------------------------------------------------------ | -| `@wrnexus/syntax` | syntax contract, feature/version metadata, ranges and diagnostics | -| `@wrnexus/compiler` | compilation cache, dependency graph, cycle-safe cache implementation | -| `@wrnexus/reactive` | watchers, resources, abort/supersession handling and cleanup scopes | -| `@wrnexus/core` | service container, lifecycle, health, Problem Details, request IDs and idempotency | -| `@wrnexus/router` | named routes, manifests, reverse URLs and app-over-package precedence | -| `@wrnexus/ssr` | structured scripts, deduplication, CSP/SRI attributes and streaming output | -| `@wrnexus/csr` | lazy package runtime loading and navigation mount/unmount lifecycle | -| `@wrnexus/plugin` | discovery and package components/runtimes/assets/styles/routes/middleware/migrations | -| `@wrnexus/dev-server` | virtual assets, TS runtime bundling, package HMR and migration integration | -| `@wrnexus/cli` | package-aware builds, inspect commands, generator and 0.4 migration | -| `@wrnexus/dev-toolbar` | package panels and platform snapshots | -| `@wrnexus/styles` | package CSS/source support, package-only styles, token and contrast audits | -| `@wrnexus/test` | request/context utilities, JSON/problem assertions, cookies and deferred helpers | -| `@wrnexus/db` | migration ordering, cursor pagination, optimistic updates and tenant helpers | -| `@wrnexus/queue` | durable stores, claims, priority, retry, dead-letter and processing safety | -| `@wrnexus/pubsub` | resilient delivery and expiring defensive presence channels | -| `@wrnexus/uploader` | safe object keys, inspection, policy enforcement and signed file tokens | -| `@wrnexus/encryption` | versioned payloads and validated rotatable keyrings | -| `@wrnexus/jwt` | key-ID signing, validated keyrings and safe decoding | -| `@wrnexus/oauth` | state/PKCE storage, refresh, OIDC discovery and safe return URLs | -| `@wrnexus/authz` | explainable decisions, owner policies, composition and filtering | -| `@wrnexus/captcha` | automatic component/runtime, providers, audio, image styles, gates and guards | -| `@wrnexus/validation` | async/cross-field refinements and OpenAPI conversion | -| `@wrnexus/i18n` | fallbacks, coverage, formatters and plural messages | -| `@wrnexus/ui` | component metadata and reference audits | -| `@wrnexus/helpers` | retry, backoff, abortable sleep, timeouts and stable serialization | -| `@wrnexus/tracking` | sampled/batched telemetry and reliable sink handling | -| `@wrnexus/ai` | provider-neutral client, fallback providers and usage metadata | -| `@wrnexus/mobile` | deep links, offline tasks and environment detection | -| `@wrnexus/native` | capability manifests, permissions and target inspection | - -## Upgrade and release tooling - -- Root/package/service versions: 0.4.0 -- VS Code extension version: 0.4.0 -- Workspace lock versions updated -- `update.ts` includes a 0.4.0 migration -- Legacy CAPTCHA scripts are archived by migration rather than silently destroyed -- Obsolete generated/release artifacts removed -- New commands: - -```bash -bun run verify:0.4 -bun run validate:0.4 -wrnexus doctor -wrnexus inspect packages . -wrnexus inspect plugins . -wrnexus inspect routes . -wrnexus inspect runtimes . -wrnexus inspect assets . -wrnexus generate system -``` - -## Documentation included - -- `README.md` -- `CHANGELOG-0.4.0.md` -- `docs/ARCHITECTURE-0.4.md` -- `docs/PACKAGE-RUNTIMES-0.4.md` -- `docs/PACKAGE-UPGRADES-0.4.md` -- `docs/UPGRADE-0.4.md` -- `docs/TEST-CHECKLIST-0.4.md` -- `VALIDATION-0.4.0.md` -- `MANIFEST-0.4.0.md` - -See `VALIDATION-0.4.0.md` for the exact checks completed and the required final Bun validation commands. diff --git a/VALIDATION-0.4.0.md b/VALIDATION-0.4.0.md deleted file mode 100644 index 05b78ae2..00000000 --- a/VALIDATION-0.4.0.md +++ /dev/null @@ -1,145 +0,0 @@ -# WRNexusJS 0.4.0 validation report - -Validation date: 2026-07-25 - -Baseline archive: - -- File: `WRNexusJS-main-current.zip` -- SHA-256: `7860543f1b0d8bb227857bb01f70c6a3719d51215e24990cc0b3e45a18211c50` - -## Result - -All validation that can be performed in this build environment passed. The repository is structurally aligned to 0.4.0, TypeScript source is syntactically and semantically valid under the project configuration used for validation, automatic package discovery works, CAPTCHA is loaded automatically without a copied `captcha.js`, editor checks pass, generated component documentation succeeds, and targeted runtime smoke checks pass. - -Bun is not installed in this environment and external package installation is unavailable. Therefore the Bun unit-test suite, ESLint, Prettier, and real Bun production builds were not executed here. Run the final commands in the last section on the target Windows/Bun environment before publishing. - -## Passed checks - -### Repository structure - -Command: - -```bash -node scripts/verify-0.4.mjs -``` - -Passed: - -- 30 `@wrnexus/*` packages aligned to version 0.4.0 -- Managed CAPTCHA service aligned to version 0.4.0 -- 73 unique updater migrations -- Package/runtime/asset/migration discovery markers -- CAPTCHA has no copied UI component or public JavaScript requirement -- Bun workspace lock structure -- VS Code extension package and lock versions -- Required 0.4 architecture, migration, runtime, testing, and documentation files - -### TypeScript - -Passed: - -- 346 TypeScript files transpiled with zero syntax diagnostics -- Strict semantic TypeScript check completed with zero diagnostics -- Compiler cache runtime-cycle smoke check passed - -The semantic check used the repository `tsconfig.json` plus temporary environment-only type roots for Node/Bun declarations. The temporary config is not included in the delivered archives. - -### WRN source - -Passed: - -- 211 `.wrn` files parsed successfully -- CAPTCHA component parses without a manual `