release: WRNexusJS 0.2.54
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ai",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/authz",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/cli",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -549,6 +549,14 @@ const MIGRATIONS: Migration[] = [
|
||||
// No generated application files require automatic migration.
|
||||
},
|
||||
},
|
||||
{
|
||||
version: "0.2.54",
|
||||
id: "essential-ui-component-system",
|
||||
description: "Adds the PDF-defined minimum and essential shared UI component system.",
|
||||
apply() {
|
||||
// No generated application files require automatic migration.
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/** Release tooling uses this to require an explicit migration entry per version. */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/compiler",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/core",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/csr",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/db",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/dev-server",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/encryption",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/helpers",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/i18n",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/jwt",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/mobile",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/native",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/oauth",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/pubsub",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/queue",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/reactive",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/router",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ssr",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/styles",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/test",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/tracking",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -67,6 +67,17 @@ body from either a named prop or the default slot.
|
||||
Also shipped: `select`, `radio`, `switch`, `progress`, `tag`, `skeleton`,
|
||||
`tooltip`, `table`, `FAQAccordion`, `AnnouncementBar`, and `BackToTop`.
|
||||
|
||||
The PDF-defined minimum release and essential build-first set also includes
|
||||
typed typography, form primitives, loading actions, combobox and multi-select,
|
||||
time/date-time and recurring schedule controls, confirmation dialogs, data
|
||||
tables, filters, desktop/mobile navigation, mega menus, marketing/product/legal
|
||||
page shells, product and metric cards, FAQ composition, pricing comparison,
|
||||
SDK tabs, legal navigation, and cookie preferences.
|
||||
|
||||
`Seo` and `StructuredData` remain framework/page concerns rather than body
|
||||
components: use the native page `seo { ... }` block and document-head APIs so
|
||||
metadata is emitted in `<head>` instead of invalid component markup.
|
||||
|
||||
The authoritative, always-current list is `uiComponentNames()` (below), which reads
|
||||
the component directory at runtime.
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
component Combobox {
|
||||
props {
|
||||
id = "combobox"
|
||||
name = ""
|
||||
label = "Choose an option"
|
||||
placeholder = "Search options"
|
||||
options = []
|
||||
required = false
|
||||
disabled = false
|
||||
class = ""
|
||||
}
|
||||
view {
|
||||
<div class="wire-field {class}"><label for="{id}" class="wire-label">{label}</label><input id="{id}" name="{name}" list="{id}-options" placeholder="{placeholder}" required="{required}" disabled="{disabled}" role="combobox" aria-autocomplete="list" class="wire-input" /><datalist id="{id}-options">{#each options as option}<option value="{option.value}">{option.label}</option>{/each}</datalist></div>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
component ConfirmationDialog {
|
||||
props {
|
||||
title = "Confirm action"
|
||||
description = "Are you sure you want to continue?"
|
||||
confirmLabel = "Confirm"
|
||||
cancelLabel = "Cancel"
|
||||
danger = false
|
||||
open = false
|
||||
class = ""
|
||||
}
|
||||
state visible = open
|
||||
view {
|
||||
<div data-show="visible" class="wire-overlay {class}" role="presentation"><section role="alertdialog" aria-modal="true" aria-labelledby="confirmation-title" aria-describedby="confirmation-description" class="wire-dialog"><h2 id="confirmation-title" class="wire-dialog__title">{title}</h2><p id="confirmation-description" class="wire-dialog__description">{description}</p><div class="wire-dialog__actions"><button type="button" class="wire-btn wire-btn--ghost" @click="visible = false">{cancelLabel}</button><button type="button" class="wire-btn {danger ? 'wire-btn--danger' : 'wire-btn--primary'}"><slot name="confirm">{confirmLabel}</slot></button></div></section></div>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
component CookiePreferencesDialog {
|
||||
props {
|
||||
title = "Cookie preferences"
|
||||
description = "Choose which optional cookies you allow. Essential cookies are always enabled."
|
||||
saveLabel = "Save preferences"
|
||||
acceptLabel = "Accept all"
|
||||
rejectLabel = "Reject optional"
|
||||
open = false
|
||||
class = ""
|
||||
}
|
||||
state visible = open
|
||||
state analytics = false
|
||||
state marketing = false
|
||||
view {
|
||||
<div data-show="visible" class="wire-overlay {class}" role="presentation"><section role="dialog" aria-modal="true" aria-labelledby="cookie-preferences-title" class="wire-dialog wire-cookie-dialog"><h2 id="cookie-preferences-title" class="wire-dialog__title">{title}</h2><p class="wire-dialog__description">{description}</p><div class="wire-cookie-list"><label class="wire-cookie-option"><span><strong>Essential</strong><small>Required for security and core functionality.</small></span><input type="checkbox" checked disabled /></label><label class="wire-cookie-option"><span><strong>Analytics</strong><small>Helps improve product performance.</small></span><input type="checkbox" checked="{analytics}" @change="analytics = event.target.checked" /></label><label class="wire-cookie-option"><span><strong>Marketing</strong><small>Supports relevant campaigns and measurement.</small></span><input type="checkbox" checked="{marketing}" @change="marketing = event.target.checked" /></label></div><div class="wire-dialog__actions wire-dialog__actions--wrap"><button type="button" class="wire-btn wire-btn--ghost" @click="analytics = false; marketing = false">{rejectLabel}</button><button type="button" class="wire-btn wire-btn--default" @click="analytics = true; marketing = true">{acceptLabel}</button><button type="button" class="wire-btn wire-btn--primary" @click="visible = false">{saveLabel}</button></div></section></div>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
component DataTable {
|
||||
props {
|
||||
caption = "Data table"
|
||||
columns = []
|
||||
rows = []
|
||||
emptyMessage = "No data available."
|
||||
striped = false
|
||||
class = ""
|
||||
}
|
||||
view {
|
||||
<div class="wire-table-wrap {class}" tabindex="0" role="region" aria-label="{caption}"><table class="wire-table {striped ? 'wire-table--striped' : ''}"><caption class="wire-visually-hidden">{caption}</caption><thead><tr>{#each columns as column}<th scope="col">{column.label}</th>{/each}</tr></thead><tbody>{#each rows as row}<tr>{#each columns as column}<td>{row[column.key]}</td>{/each}</tr>{:empty}<tr><td colspan="{columns.length}">{emptyMessage}</td></tr>{/each}</tbody></table></div>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
component DateTimePicker {
|
||||
props {
|
||||
id = "datetime-picker"
|
||||
name = "datetime"
|
||||
label = "Date and time"
|
||||
value = ""
|
||||
min = ""
|
||||
max = ""
|
||||
required = false
|
||||
disabled = false
|
||||
class = ""
|
||||
}
|
||||
view { <div class="wire-field {class}"><label for="{id}" class="wire-label">{label}</label><input id="{id}" name="{name}" type="datetime-local" value="{value}" min="{min}" max="{max}" required="{required}" disabled="{disabled}" class="wire-input" /></div> }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
component DesktopNavigation {
|
||||
props {
|
||||
label = "Primary navigation"
|
||||
items = []
|
||||
class = ""
|
||||
}
|
||||
view { <nav aria-label="{label}" class="wire-desktop-nav {class}"><ul>{#each items as item}<li><a href="{item.href}" aria-current="{item.current ? 'page' : 'false'}">{item.label}</a></li>{/each}</ul></nav> }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
component FAQ {
|
||||
props {
|
||||
eyebrow = ""
|
||||
title = "Frequently asked questions"
|
||||
description = ""
|
||||
items = []
|
||||
centered = true
|
||||
allowMultiple = false
|
||||
defaultOpenIndex = 0
|
||||
}
|
||||
view { <FAQAccordion eyebrow="{eyebrow}" title="{title}" description="{description}" items="{items}" centered="{centered}" allowMultiple="{allowMultiple}" defaultOpenIndex="{defaultOpenIndex}" /> }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
component FilterBar {
|
||||
props {
|
||||
label = "Filters"
|
||||
clearLabel = "Clear filters"
|
||||
showClear = true
|
||||
class = ""
|
||||
}
|
||||
view { <section aria-label="{label}" class="wire-filter-bar {class}"><div class="wire-filter-bar__controls"><slot /></div><button data-show="showClear" type="reset" class="wire-btn wire-btn--ghost wire-btn--sm">{clearLabel}</button></section> }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
component Form {
|
||||
props {
|
||||
action = ""
|
||||
method = "post"
|
||||
name = ""
|
||||
loading = false
|
||||
class = ""
|
||||
}
|
||||
view {
|
||||
<form action="{action}" method="{method}" name="{name}" aria-busy="{loading}" class="wire-form {class}"><slot /></form>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
component FormError {
|
||||
props {
|
||||
id = ""
|
||||
message = ""
|
||||
class = ""
|
||||
}
|
||||
view { <p id="{id}" role="alert" aria-live="polite" class="wire-field-message wire-field-message--error {class}">{message}<slot /></p> }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
component FormHelpText {
|
||||
props {
|
||||
id = ""
|
||||
text = ""
|
||||
class = ""
|
||||
}
|
||||
view { <p id="{id}" class="wire-field-message wire-field-message--help {class}">{text}<slot /></p> }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
component FormLabel {
|
||||
props {
|
||||
for = ""
|
||||
label = "Label"
|
||||
required = false
|
||||
optional = false
|
||||
class = ""
|
||||
}
|
||||
view {
|
||||
<label for="{for}" class="wire-label {class}">{label}<span data-show="required" class="wire-required" aria-hidden="true"> *</span><span data-show="optional && !required" class="wire-optional"> (optional)</span></label>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
component LegalPageShell {
|
||||
props {
|
||||
class = ""
|
||||
}
|
||||
view { <div class="wire-page-shell wire-page-shell--legal {class}"><aside class="wire-page-shell__aside"><slot name="navigation" /></aside><main class="wire-page-shell__main"><slot /></main></div> }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
component LegalTableOfContents {
|
||||
props {
|
||||
title = "On this page"
|
||||
items = []
|
||||
class = ""
|
||||
}
|
||||
view { <nav aria-label="{title}" class="wire-legal-toc {class}"><h2>{title}</h2><ol>{#each items as item}<li><a href="{item.href}">{item.label}</a></li>{/each}</ol></nav> }
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
component LoadingButton {
|
||||
props {
|
||||
label = "Continue"
|
||||
loadingLabel = "Loading…"
|
||||
loading = false
|
||||
disabled = false
|
||||
type = "button"
|
||||
variant = "primary"
|
||||
class = ""
|
||||
}
|
||||
view {
|
||||
<button type="{type}" disabled="{disabled || loading}" aria-disabled="{disabled || loading}" aria-busy="{loading}" class="wire-btn wire-btn--{variant} wire-loading-button {class}"><span data-show="loading" class="wire-spinner wire-spinner--inline" aria-hidden="true"></span><span>{loading ? loadingLabel : label}</span></button>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
component MarketingPageShell {
|
||||
props {
|
||||
class = ""
|
||||
}
|
||||
view { <div class="wire-page-shell wire-page-shell--marketing {class}"><slot /></div> }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
component MegaMenu {
|
||||
props {
|
||||
label = "Explore"
|
||||
sections = []
|
||||
class = ""
|
||||
}
|
||||
state open = false
|
||||
view {
|
||||
<div class="wire-mega-menu {class}"><button type="button" class="wire-mega-menu__trigger" aria-expanded="{open}" @click="open = !open">{label}<span aria-hidden="true">⌄</span></button><div data-show="open" class="wire-mega-menu__panel">{#each sections as section}<section><h3>{section.title}</h3><ul>{#each section.items as item}<li><a href="{item.href}">{item.label}</a></li>{/each}</ul></section>{/each}</div></div>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
component MetricGrid {
|
||||
props {
|
||||
label = "Key metrics"
|
||||
metrics = []
|
||||
class = ""
|
||||
}
|
||||
view { <section aria-label="{label}" class="wire-metric-grid {class}">{#each metrics as metric}<article class="wire-metric"><p class="wire-metric__value">{metric.value}</p><p class="wire-metric__label">{metric.label}</p><p data-show="metric.description" class="wire-metric__description">{metric.description}</p></article>{/each}</section> }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
component MobileNavigation {
|
||||
props {
|
||||
label = "Menu"
|
||||
closeLabel = "Close menu"
|
||||
items = []
|
||||
class = ""
|
||||
}
|
||||
state open = false
|
||||
view {
|
||||
<div class="wire-mobile-nav {class}"><button type="button" class="wire-btn wire-btn--ghost" aria-expanded="{open}" aria-controls="wire-mobile-navigation" @click="open = !open">{open ? closeLabel : label}</button><nav id="wire-mobile-navigation" data-show="open" aria-label="Mobile navigation" class="wire-mobile-nav__panel"><ul>{#each items as item}<li><a href="{item.href}">{item.label}</a></li>{/each}</ul></nav></div>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
component MultiSelect {
|
||||
props {
|
||||
id = "multi-select"
|
||||
name = ""
|
||||
label = "Choose options"
|
||||
options = []
|
||||
required = false
|
||||
disabled = false
|
||||
size = 5
|
||||
class = ""
|
||||
}
|
||||
view {
|
||||
<div class="wire-field {class}"><label for="{id}" class="wire-label">{label}</label><select id="{id}" name="{name}" multiple required="{required}" disabled="{disabled}" size="{size}" class="wire-input wire-multiselect">{#each options as option}<option value="{option.value}" selected="{option.selected}">{option.label}</option>{/each}</select></div>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
component PricingComparisonTable {
|
||||
props {
|
||||
caption = "Plan comparison"
|
||||
plans = []
|
||||
features = []
|
||||
class = ""
|
||||
}
|
||||
view { <div class="wire-table-wrap {class}" tabindex="0" role="region" aria-label="{caption}"><table class="wire-table wire-comparison-table"><caption class="wire-visually-hidden">{caption}</caption><thead><tr><th scope="col">Feature</th>{#each plans as plan}<th scope="col">{plan.name}</th>{/each}</tr></thead><tbody>{#each features as feature}<tr><th scope="row">{feature.label}</th>{#each feature.values as value}<td>{value}</td>{/each}</tr>{/each}</tbody></table></div> }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
component ProductCard {
|
||||
props {
|
||||
eyebrow = "Product"
|
||||
title = "Product name"
|
||||
description = ""
|
||||
href = "#"
|
||||
actionLabel = "Learn more"
|
||||
status = ""
|
||||
class = ""
|
||||
}
|
||||
view { <article class="wire-product-card {class}"><div class="wire-product-card__meta"><span class="wire-eyebrow">{eyebrow}</span><span data-show="status" class="wire-badge">{status}</span></div><h3>{title}</h3><p>{description}</p><a href="{href}" class="wire-product-card__link">{actionLabel}<span aria-hidden="true"> →</span></a></article> }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
component ProductPageShell {
|
||||
props {
|
||||
class = ""
|
||||
}
|
||||
view { <div class="wire-page-shell wire-page-shell--product {class}"><slot /></div> }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
component ProductsMegaMenu {
|
||||
props {
|
||||
label = "Products"
|
||||
sections = []
|
||||
class = ""
|
||||
}
|
||||
view { <MegaMenu label="{label}" sections="{sections}" class="{class}" /> }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
component QuietHoursPicker {
|
||||
props {
|
||||
label = "Quiet hours"
|
||||
startName = "quietStart"
|
||||
endName = "quietEnd"
|
||||
start = "22:00"
|
||||
end = "08:00"
|
||||
timezone = "UTC"
|
||||
disabled = false
|
||||
class = ""
|
||||
}
|
||||
view {
|
||||
<fieldset class="wire-fieldset {class}" disabled="{disabled}"><legend class="wire-label">{label}</legend><div class="wire-form-row"><label class="wire-field"><span class="wire-label">From</span><input type="time" name="{startName}" value="{start}" class="wire-input" /></label><label class="wire-field"><span class="wire-label">Until</span><input type="time" name="{endName}" value="{end}" class="wire-input" /></label></div><p class="wire-field-message wire-field-message--help">Timezone: {timezone}</p></fieldset>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
component RecurringSchedulePicker {
|
||||
props {
|
||||
id = "recurring-schedule"
|
||||
name = "recurrence"
|
||||
label = "Repeat"
|
||||
value = "none"
|
||||
disabled = false
|
||||
class = ""
|
||||
}
|
||||
view {
|
||||
<div class="wire-field {class}"><label for="{id}" class="wire-label">{label}</label><select id="{id}" name="{name}" disabled="{disabled}" class="wire-input"><option value="none" selected="{value === 'none'}">Does not repeat</option><option value="daily" selected="{value === 'daily'}">Daily</option><option value="weekly" selected="{value === 'weekly'}">Weekly</option><option value="monthly" selected="{value === 'monthly'}">Monthly</option><option value="yearly" selected="{value === 'yearly'}">Yearly</option></select></div>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
component SDKTabs {
|
||||
props {
|
||||
label = "SDK languages"
|
||||
tabs = []
|
||||
defaultIndex = 0
|
||||
class = ""
|
||||
}
|
||||
state active = defaultIndex
|
||||
view { <section class="wire-sdk-tabs {class}"><div role="tablist" aria-label="{label}" class="wire-tabs">{#each tabs as tab, index}<button type="button" role="tab" aria-selected="{active === index}" class="wire-tab" @click="active = index">{tab.label}</button>{/each}</div>{#each tabs as tab, index}<div role="tabpanel" data-show="active === index" class="wire-sdk-tabs__panel"><pre><code>{tab.code}</code></pre></div>{/each}</section> }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
component TimePicker {
|
||||
props {
|
||||
id = "time-picker"
|
||||
name = "time"
|
||||
label = "Time"
|
||||
value = ""
|
||||
min = ""
|
||||
max = ""
|
||||
step = 60
|
||||
required = false
|
||||
disabled = false
|
||||
class = ""
|
||||
}
|
||||
view { <div class="wire-field {class}"><label for="{id}" class="wire-label">{label}</label><input id="{id}" name="{name}" type="time" value="{value}" min="{min}" max="{max}" step="{step}" required="{required}" disabled="{disabled}" class="wire-input" /></div> }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
component Typography {
|
||||
props {
|
||||
as = "p"
|
||||
variant = "body"
|
||||
align = "start"
|
||||
class = ""
|
||||
}
|
||||
view {
|
||||
<div class="wire-type wire-type--{variant} wire-text--{align} {class}"><slot /></div>
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ui",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -13,6 +13,52 @@ test("bundled UI assets are discoverable and readable", () => {
|
||||
expect(uiCss()).toContain("--wire-");
|
||||
});
|
||||
|
||||
test("PDF minimum-release and essential build-first components are bundled", () => {
|
||||
const required = [
|
||||
"Typography",
|
||||
"Form",
|
||||
"FormLabel",
|
||||
"FormHelpText",
|
||||
"FormError",
|
||||
"LoadingButton",
|
||||
"Combobox",
|
||||
"MultiSelect",
|
||||
"TimePicker",
|
||||
"DateTimePicker",
|
||||
"RecurringSchedulePicker",
|
||||
"QuietHoursPicker",
|
||||
"ConfirmationDialog",
|
||||
"DataTable",
|
||||
"FilterBar",
|
||||
"MegaMenu",
|
||||
"DesktopNavigation",
|
||||
"ProductsMegaMenu",
|
||||
"MobileNavigation",
|
||||
"MarketingPageShell",
|
||||
"ProductPageShell",
|
||||
"LegalPageShell",
|
||||
"ProductCard",
|
||||
"MetricGrid",
|
||||
"FAQ",
|
||||
"PricingComparisonTable",
|
||||
"SDKTabs",
|
||||
"LegalTableOfContents",
|
||||
"CookiePreferencesDialog",
|
||||
];
|
||||
|
||||
expect(uiComponentNames()).toEqual(expect.arrayContaining(required));
|
||||
});
|
||||
|
||||
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");
|
||||
});
|
||||
|
||||
test.each(uiComponentNames())("bundled UI component %s compiles", (name) => {
|
||||
const path = join(uiComponentsDir(), `${name}.wrn`);
|
||||
expect(() => compileWireFile(readFileSync(path, "utf8"), path)).not.toThrow();
|
||||
|
||||
@@ -537,3 +537,418 @@
|
||||
outline: 2px solid rgb(124 58 237);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* --- Component-system foundations --------------------------------------- */
|
||||
.wire-type {
|
||||
margin: 0;
|
||||
color: var(--wire-color-text);
|
||||
}
|
||||
.wire-type--display {
|
||||
font-size: clamp(2.25rem, 7vw, 4.75rem);
|
||||
line-height: 1.02;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
.wire-type--heading {
|
||||
font-size: clamp(1.75rem, 4vw, 3rem);
|
||||
line-height: 1.1;
|
||||
font-weight: 750;
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
.wire-type--lead {
|
||||
font-size: clamp(1.05rem, 2vw, 1.25rem);
|
||||
line-height: 1.65;
|
||||
color: var(--wire-color-muted);
|
||||
}
|
||||
.wire-type--body {
|
||||
font-size: 1rem;
|
||||
line-height: 1.65;
|
||||
}
|
||||
.wire-type--small {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.wire-text--center {
|
||||
text-align: center;
|
||||
}
|
||||
.wire-text--end {
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
.wire-form {
|
||||
display: grid;
|
||||
gap: 1.25rem;
|
||||
width: 100%;
|
||||
}
|
||||
.wire-form-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
.wire-field,
|
||||
.wire-fieldset {
|
||||
display: grid;
|
||||
gap: 0.45rem;
|
||||
min-width: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.wire-label {
|
||||
color: var(--wire-color-text);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 650;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.wire-required,
|
||||
.wire-field-message--error {
|
||||
color: var(--wire-color-danger);
|
||||
}
|
||||
.wire-optional,
|
||||
.wire-field-message--help {
|
||||
color: var(--wire-color-muted);
|
||||
font-weight: 400;
|
||||
}
|
||||
.wire-field-message {
|
||||
margin: 0;
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.wire-input:disabled,
|
||||
.wire-btn:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.58;
|
||||
}
|
||||
.wire-input[aria-invalid="true"] {
|
||||
border-color: var(--wire-color-danger);
|
||||
}
|
||||
.wire-multiselect {
|
||||
min-height: 8rem;
|
||||
}
|
||||
.wire-loading-button {
|
||||
min-height: 44px;
|
||||
}
|
||||
.wire-spinner--inline {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.wire-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1000;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 1rem;
|
||||
background: rgb(0 0 0 / 0.55);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
.wire-dialog {
|
||||
width: min(100%, 32rem);
|
||||
max-height: calc(100dvh - 2rem);
|
||||
overflow: auto;
|
||||
padding: clamp(1.25rem, 4vw, 2rem);
|
||||
color: var(--wire-color-text);
|
||||
background: var(--wire-color-surface);
|
||||
border: 1px solid var(--wire-color-border);
|
||||
border-radius: var(--wire-radius);
|
||||
box-shadow: var(--wire-shadow-1);
|
||||
}
|
||||
.wire-dialog__title {
|
||||
margin: 0;
|
||||
font-size: 1.35rem;
|
||||
line-height: 1.25;
|
||||
}
|
||||
.wire-dialog__description {
|
||||
margin: 0.75rem 0 0;
|
||||
color: var(--wire-color-muted);
|
||||
line-height: 1.6;
|
||||
}
|
||||
.wire-dialog__actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.75rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
.wire-dialog__actions--wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.wire-filter-bar {
|
||||
display: flex;
|
||||
align-items: end;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
background: var(--wire-color-surface);
|
||||
border: 1px solid var(--wire-color-border);
|
||||
border-radius: var(--wire-radius);
|
||||
}
|
||||
.wire-filter-bar__controls {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-wrap: wrap;
|
||||
align-items: end;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
.wire-table--striped tbody tr:nth-child(even) {
|
||||
background: var(--wire-color-surface-2);
|
||||
}
|
||||
.wire-comparison-table {
|
||||
min-width: 42rem;
|
||||
}
|
||||
|
||||
.wire-desktop-nav > ul,
|
||||
.wire-mobile-nav ul,
|
||||
.wire-mega-menu ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.wire-desktop-nav > ul {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
.wire-desktop-nav a,
|
||||
.wire-mega-menu__trigger {
|
||||
display: inline-flex;
|
||||
min-height: 44px;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
padding: 0.6rem 0.8rem;
|
||||
color: var(--wire-color-text);
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: var(--wire-radius-sm);
|
||||
text-decoration: none;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
.wire-desktop-nav a:hover,
|
||||
.wire-mega-menu__trigger:hover {
|
||||
background: var(--wire-color-surface-2);
|
||||
}
|
||||
.wire-mega-menu {
|
||||
position: relative;
|
||||
}
|
||||
.wire-mega-menu__panel {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
top: calc(100% + 0.5rem);
|
||||
left: 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(10rem, 1fr));
|
||||
gap: 1.25rem;
|
||||
width: min(46rem, calc(100vw - 2rem));
|
||||
padding: 1.25rem;
|
||||
color: var(--wire-color-text);
|
||||
background: var(--wire-color-surface);
|
||||
border: 1px solid var(--wire-color-border);
|
||||
border-radius: var(--wire-radius);
|
||||
box-shadow: var(--wire-shadow-1);
|
||||
}
|
||||
.wire-mega-menu__panel h3 {
|
||||
margin: 0 0 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.wire-mega-menu__panel a,
|
||||
.wire-mobile-nav__panel a {
|
||||
display: flex;
|
||||
min-height: 44px;
|
||||
align-items: center;
|
||||
color: var(--wire-color-text);
|
||||
text-decoration: none;
|
||||
}
|
||||
.wire-mobile-nav {
|
||||
display: none;
|
||||
}
|
||||
.wire-mobile-nav__panel {
|
||||
position: fixed;
|
||||
inset: 4rem 1rem auto;
|
||||
z-index: 100;
|
||||
max-height: calc(100dvh - 5rem);
|
||||
overflow: auto;
|
||||
padding: 1rem;
|
||||
background: var(--wire-color-surface);
|
||||
border: 1px solid var(--wire-color-border);
|
||||
border-radius: var(--wire-radius);
|
||||
box-shadow: var(--wire-shadow-1);
|
||||
}
|
||||
|
||||
.wire-page-shell {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
color: var(--wire-color-text);
|
||||
background: var(--wire-color-bg);
|
||||
}
|
||||
.wire-page-shell--marketing,
|
||||
.wire-page-shell--product {
|
||||
overflow: clip;
|
||||
}
|
||||
.wire-page-shell--legal {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(14rem, 18rem) minmax(0, 1fr);
|
||||
gap: clamp(2rem, 5vw, 5rem);
|
||||
max-width: 80rem;
|
||||
margin-inline: auto;
|
||||
padding: clamp(1rem, 4vw, 3rem);
|
||||
}
|
||||
.wire-page-shell__aside {
|
||||
position: sticky;
|
||||
top: 1rem;
|
||||
align-self: start;
|
||||
}
|
||||
.wire-page-shell__main {
|
||||
min-width: 0;
|
||||
max-width: 52rem;
|
||||
}
|
||||
|
||||
.wire-product-card,
|
||||
.wire-metric {
|
||||
padding: clamp(1rem, 3vw, 1.5rem);
|
||||
color: var(--wire-color-text);
|
||||
background: var(--wire-color-surface);
|
||||
border: 1px solid var(--wire-color-border);
|
||||
border-radius: var(--wire-radius);
|
||||
box-shadow: var(--wire-shadow-1);
|
||||
}
|
||||
.wire-product-card {
|
||||
display: grid;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
.wire-product-card__meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
.wire-product-card h3,
|
||||
.wire-product-card p {
|
||||
margin: 0;
|
||||
}
|
||||
.wire-product-card p {
|
||||
color: var(--wire-color-muted);
|
||||
line-height: 1.6;
|
||||
}
|
||||
.wire-product-card__link {
|
||||
color: var(--wire-color-primary);
|
||||
font-weight: 650;
|
||||
text-decoration: none;
|
||||
}
|
||||
.wire-eyebrow {
|
||||
color: var(--wire-color-primary);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 750;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.wire-metric-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
.wire-metric__value {
|
||||
margin: 0;
|
||||
font-size: clamp(1.75rem, 4vw, 2.5rem);
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
.wire-metric__label {
|
||||
margin: 0.35rem 0 0;
|
||||
font-weight: 650;
|
||||
}
|
||||
.wire-metric__description {
|
||||
margin: 0.35rem 0 0;
|
||||
color: var(--wire-color-muted);
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.wire-sdk-tabs__panel {
|
||||
overflow-x: auto;
|
||||
border: 1px solid var(--wire-color-border);
|
||||
border-radius: 0 0 var(--wire-radius) var(--wire-radius);
|
||||
background: var(--wire-color-surface-2);
|
||||
}
|
||||
.wire-sdk-tabs__panel pre {
|
||||
margin: 0;
|
||||
min-width: max-content;
|
||||
padding: 1rem;
|
||||
}
|
||||
.wire-legal-toc {
|
||||
padding: 1rem;
|
||||
border-left: 2px solid var(--wire-color-border);
|
||||
}
|
||||
.wire-legal-toc h2 {
|
||||
margin: 0 0 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.wire-legal-toc ol {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
margin: 0;
|
||||
padding-left: 1.25rem;
|
||||
}
|
||||
.wire-legal-toc a {
|
||||
color: var(--wire-color-muted);
|
||||
text-decoration: none;
|
||||
}
|
||||
.wire-cookie-list {
|
||||
display: grid;
|
||||
gap: 0.75rem;
|
||||
margin-top: 1.25rem;
|
||||
}
|
||||
.wire-cookie-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
min-height: 44px;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid var(--wire-color-border);
|
||||
border-radius: var(--wire-radius-sm);
|
||||
}
|
||||
.wire-cookie-option span {
|
||||
display: grid;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
.wire-cookie-option small {
|
||||
color: var(--wire-color-muted);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.wire-desktop-nav {
|
||||
display: none;
|
||||
}
|
||||
.wire-mobile-nav {
|
||||
display: block;
|
||||
}
|
||||
.wire-mega-menu__panel {
|
||||
position: static;
|
||||
grid-template-columns: 1fr;
|
||||
width: 100%;
|
||||
box-shadow: none;
|
||||
}
|
||||
.wire-page-shell--legal {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.wire-page-shell__aside {
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.wire-form-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.wire-filter-bar {
|
||||
align-items: stretch;
|
||||
flex-direction: column;
|
||||
}
|
||||
.wire-filter-bar__controls {
|
||||
display: grid;
|
||||
}
|
||||
.wire-dialog__actions > * {
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/uploader",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/validation",
|
||||
"version": "0.2.53",
|
||||
"version": "0.2.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
Reference in New Issue
Block a user