release: WRNexusJS 0.5.12
This commit is contained in:
+171
-9
@@ -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
|
||||
|
||||
|
||||
+412
-322
@@ -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."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,29 @@ component Columns {
|
||||
maxWidth = "xl"
|
||||
class = ""
|
||||
}
|
||||
|
||||
view {
|
||||
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--columns wire-next--gap-{gap} wire-next--columns-{columns} wire-next--max-{maxWidth} {class}"><slot /></div>
|
||||
<div
|
||||
data-ui-component="Columns"
|
||||
data-size='{size}'
|
||||
data-color='{color}'
|
||||
data-columns='{columns}'
|
||||
data-gap='{gap}'
|
||||
class='grid w-full grid-cols-1 items-start {class}'
|
||||
class:max-w-3xl='maxWidth === "md"'
|
||||
class:max-w-5xl='maxWidth === "lg"'
|
||||
class:max-w-7xl='maxWidth === "xl"'
|
||||
class:max-w-screen-2xl='maxWidth === "2xl"'
|
||||
class:max-w-none='maxWidth === "full"'
|
||||
class:md:grid-cols-2='columns >= 2'
|
||||
class:lg:grid-cols-3='columns === 3'
|
||||
class:lg:grid-cols-4='columns === 4'
|
||||
class:gap-3='gap === "sm"'
|
||||
class:gap-6='gap === "md"'
|
||||
class:gap-10='gap === "lg"'
|
||||
class:gap-14='gap === "xl"'
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
<figure class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--image {rounded ? 'wire-next--rounded' : ''} {class}">
|
||||
<img src="{src}" alt="{alt}" width="{width}" height="{height}" loading="{loading}" />
|
||||
<slot />
|
||||
<figure
|
||||
data-ui-component="Image"
|
||||
class='relative m-0 overflow-hidden bg-[var(--wire-color-surface-soft)] {class}'
|
||||
class:rounded-2xl='rounded'
|
||||
>
|
||||
{#if src}
|
||||
<img
|
||||
src='{src}'
|
||||
alt='{alt}'
|
||||
width='{width}'
|
||||
height='{height}'
|
||||
loading='{loading}'
|
||||
decoding="async"
|
||||
class="block h-auto w-full object-cover transition duration-300"
|
||||
class:aspect-square='size === "square"'
|
||||
class:aspect-video='size === "video"'
|
||||
class:aspect-[4/3]='size === "landscape"'
|
||||
class:aspect-[3/4]='size === "portrait"'
|
||||
/>
|
||||
{:else}
|
||||
<div
|
||||
class="flex min-h-48 w-full items-center justify-center text-[var(--wire-color-text-muted)]"
|
||||
role="img"
|
||||
aria-label='{alt || "Image placeholder"}'
|
||||
>
|
||||
<span class="icon-[lucide--image] size-8" aria-hidden="true"></span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<slot></slot>
|
||||
</figure>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
<a {...attrs} href="{href}" target="{target}" rel="{rel}" class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--link {class}"><slot>{label}</slot>{#if external}<span aria-hidden="true">↗</span>{/if}</a>
|
||||
<a
|
||||
data-ui-component="Link"
|
||||
href='{href}'
|
||||
target='{target}'
|
||||
rel='{external ? (rel || "noopener noreferrer") : rel}'
|
||||
class='inline-flex min-w-0 items-center gap-1.5 rounded-md font-semibold underline-offset-4 outline-none transition-colors focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--wire-color-background)] {class}'
|
||||
class:text-xs='size === "xs"'
|
||||
class:text-sm='size === "sm" || size === "default"'
|
||||
class:text-base='size === "md"'
|
||||
class:text-lg='size === "lg"'
|
||||
class:text-[var(--wire-color-primary)]='color === "primary"'
|
||||
class:hover:text-[var(--wire-color-primary-hover)]='color === "primary"'
|
||||
class:text-[var(--wire-color-secondary)]='color === "secondary"'
|
||||
class:hover:text-[var(--wire-color-secondary-hover)]='color === "secondary"'
|
||||
class:text-[var(--wire-color-success)]='color === "success"'
|
||||
class:text-[var(--wire-color-warning-text)]='color === "warning"'
|
||||
class:text-[var(--wire-color-danger)]='color === "danger"'
|
||||
class:text-[var(--wire-color-info)]='color === "info"'
|
||||
class:text-[var(--wire-color-text)]='color === "neutral"'
|
||||
class:hover:underline='external === false'
|
||||
>
|
||||
<span class="truncate">{label}</span>
|
||||
|
||||
{#if external}
|
||||
<span
|
||||
class="icon-[lucide--external-link] size-3.5 shrink-0"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
{/if}
|
||||
|
||||
<slot></slot>
|
||||
</a>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--list wire-next--variant-{variant} {class}">
|
||||
{#if title}<strong>{title}</strong>{/if}
|
||||
{#if description}<p>{description}</p>{/if}
|
||||
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||
<slot />
|
||||
<section
|
||||
data-ui-component="List"
|
||||
aria-label='{title}'
|
||||
class='w-full {class}'
|
||||
>
|
||||
{#if title || description}
|
||||
<header class="mb-4">
|
||||
{#if title}
|
||||
<h3 class="text-lg font-bold text-[var(--wire-color-text)]">{title}</h3>
|
||||
{/if}
|
||||
{#if description}
|
||||
<p class="mt-1 text-sm leading-6 text-[var(--wire-color-text-muted)]">{description}</p>
|
||||
{/if}
|
||||
</header>
|
||||
{/if}
|
||||
|
||||
<ul
|
||||
class="overflow-hidden"
|
||||
class:divide-y='variant === "default" || variant === "divided"'
|
||||
class:divide-[var(--wire-color-border)]='variant === "default" || variant === "divided"'
|
||||
class:rounded-2xl='variant === "card"'
|
||||
class:border='variant === "card"'
|
||||
class:border-[var(--wire-color-border)]='variant === "card"'
|
||||
class:bg-[var(--wire-color-surface-raised)]='variant === "card"'
|
||||
class:space-y-3='variant === "separated"'
|
||||
>
|
||||
{#each items as item, index}
|
||||
<li
|
||||
class="group min-w-0"
|
||||
class:rounded-xl='variant === "separated"'
|
||||
class:border='variant === "separated"'
|
||||
class:border-[var(--wire-color-border)]='variant === "separated"'
|
||||
class:bg-[var(--wire-color-surface-raised)]='variant === "separated"'
|
||||
>
|
||||
{#if item.href}
|
||||
<a
|
||||
href='{item.href}'
|
||||
class="flex min-w-0 items-start gap-3 px-4 py-3 outline-none transition hover:bg-[var(--wire-color-surface-soft)] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--wire-color-focus)]"
|
||||
class:px-3='size === "sm"'
|
||||
class:py-2.5='size === "sm"'
|
||||
class:px-5='size === "lg"'
|
||||
class:py-4='size === "lg"'
|
||||
@click='event.currentTarget.dispatchEvent(new CustomEvent("select", { bubbles: true, detail: { item: item, index: index } }))'
|
||||
>
|
||||
{#if item.icon}
|
||||
<span class="flex size-10 shrink-0 items-center justify-center rounded-xl bg-[var(--wire-color-primary-soft)] text-[var(--wire-color-primary)]">
|
||||
<span class='{item.icon + " size-5"}' aria-hidden="true"></span>
|
||||
</span>
|
||||
{/if}
|
||||
{#if item.imageSrc}
|
||||
<img src='{item.imageSrc}' alt='{item.imageAlt || ""}' class="size-12 shrink-0 rounded-xl object-cover" loading="lazy" />
|
||||
{/if}
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<p class="truncate font-semibold text-[var(--wire-color-text)]">{item.title || item.label}</p>
|
||||
{#if item.meta}
|
||||
<span class="shrink-0 text-xs text-[var(--wire-color-text-muted)]">{item.meta}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{#if item.description}
|
||||
<p class="mt-1 line-clamp-2 text-sm leading-5 text-[var(--wire-color-text-muted)]">{item.description}</p>
|
||||
{/if}
|
||||
{#if item.badge}
|
||||
<span class="mt-2 inline-flex rounded-full bg-[var(--wire-color-primary-soft)] px-2.5 py-1 text-xs font-semibold text-[var(--wire-color-primary)]">{item.badge}</span>
|
||||
{/if}
|
||||
</div>
|
||||
<span class="icon-[lucide--chevron-right] mt-1 size-4 shrink-0 text-[var(--wire-color-text-muted)] transition group-hover:translate-x-0.5 group-hover:text-[var(--wire-color-primary)]" aria-hidden="true"></span>
|
||||
</a>
|
||||
{:else}
|
||||
<div class="flex min-w-0 items-start gap-3 px-4 py-3">
|
||||
{#if item.icon}
|
||||
<span class="flex size-10 shrink-0 items-center justify-center rounded-xl bg-[var(--wire-color-primary-soft)] text-[var(--wire-color-primary)]">
|
||||
<span class='{item.icon + " size-5"}' aria-hidden="true"></span>
|
||||
</span>
|
||||
{/if}
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="font-semibold text-[var(--wire-color-text)]">{item.title || item.label}</p>
|
||||
{#if item.description}
|
||||
<p class="mt-1 text-sm leading-5 text-[var(--wire-color-text-muted)]">{item.description}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</li>
|
||||
{:empty}
|
||||
<li class="rounded-xl border border-dashed border-[var(--wire-color-border)] p-6 text-center text-sm text-[var(--wire-color-text-muted)]">
|
||||
No items available.
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
<slot></slot>
|
||||
</section>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--map wire-next--variant-{variant} {class}">
|
||||
{#if title}<strong>{title}</strong>{/if}
|
||||
{#if description}<p>{description}</p>{/if}
|
||||
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||
<slot />
|
||||
<section
|
||||
data-ui-component="Map"
|
||||
aria-label='{title}'
|
||||
class='overflow-hidden rounded-2xl border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] shadow-sm {class}'
|
||||
>
|
||||
{#if title || description}
|
||||
<header class="flex items-start justify-between gap-4 border-b border-[var(--wire-color-border)] p-5">
|
||||
<div>
|
||||
{#if title}
|
||||
<h3 class="text-lg font-bold text-[var(--wire-color-text)]">{title}</h3>
|
||||
{/if}
|
||||
{#if description}
|
||||
<p class="mt-1 text-sm leading-6 text-[var(--wire-color-text-muted)]">{description}</p>
|
||||
{/if}
|
||||
</div>
|
||||
<span class="flex size-10 shrink-0 items-center justify-center rounded-xl bg-[var(--wire-color-primary-soft)] text-[var(--wire-color-primary)]">
|
||||
<span class="icon-[lucide--map] size-5" aria-hidden="true"></span>
|
||||
</span>
|
||||
</header>
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="relative isolate overflow-hidden bg-[var(--wire-color-surface-soft)]"
|
||||
class:h-64='size === "sm"'
|
||||
class:h-80='size === "default" || size === "md"'
|
||||
class:h-[28rem]='size === "lg"'
|
||||
>
|
||||
<div
|
||||
class="pointer-events-none absolute inset-0 opacity-50"
|
||||
style="background-image: linear-gradient(var(--wire-color-border) 1px, transparent 1px), linear-gradient(90deg, var(--wire-color-border) 1px, transparent 1px); background-size: 32px 32px;"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
|
||||
<div class="absolute inset-0 flex items-center justify-center p-6">
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
||||
{#if items.length > 0}
|
||||
{#each items as item, index}
|
||||
<button
|
||||
type="button"
|
||||
aria-label='{item.label || item.title || "Map marker"}'
|
||||
class="absolute inline-flex size-10 items-center justify-center rounded-full border-4 border-[var(--wire-color-surface-raised)] bg-[var(--wire-color-primary)] text-[var(--wire-color-on-primary)] shadow-lg transition hover:scale-110 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)]"
|
||||
style='left: {item.x || (20 + index * 12)}%; top: {item.y || (30 + (index % 3) * 18)}%;'
|
||||
@click='event.currentTarget.dispatchEvent(new CustomEvent("markerClick", { bubbles: true, detail: item })); event.currentTarget.dispatchEvent(new CustomEvent("select", { bubbles: true, detail: item }))'
|
||||
>
|
||||
<span class='{item.icon || "icon-[lucide--map-pin]"}' aria-hidden="true"></span>
|
||||
</button>
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
<div class="absolute bottom-4 right-4 flex flex-col gap-2">
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Zoom in"
|
||||
class="inline-flex size-10 items-center justify-center rounded-xl border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] text-[var(--wire-color-text)] shadow-sm transition hover:bg-[var(--wire-color-surface-soft)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)]"
|
||||
@click='event.currentTarget.dispatchEvent(new CustomEvent("zoom", { bubbles: true, detail: { direction: "in" } }))'
|
||||
>
|
||||
<span class="icon-[lucide--plus] size-4" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Zoom out"
|
||||
class="inline-flex size-10 items-center justify-center rounded-xl border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] text-[var(--wire-color-text)] shadow-sm transition hover:bg-[var(--wire-color-surface-soft)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)]"
|
||||
@click='event.currentTarget.dispatchEvent(new CustomEvent("zoom", { bubbles: true, detail: { direction: "out" } }))'
|
||||
>
|
||||
<span class="icon-[lucide--minus] size-4" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--marquee wire-next--variant-{variant} {class}">
|
||||
{#if title}<strong>{title}</strong>{/if}
|
||||
{#if description}<p>{description}</p>{/if}
|
||||
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||
<slot />
|
||||
<section
|
||||
data-ui-component="Marquee"
|
||||
aria-label='{title}'
|
||||
class='overflow-hidden border-y border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] {class}'
|
||||
>
|
||||
<div class="flex items-stretch">
|
||||
{#if title}
|
||||
<div class="relative z-10 flex shrink-0 items-center gap-2 border-r border-[var(--wire-color-border)] bg-[var(--wire-color-primary)] px-4 py-3 text-[var(--wire-color-on-primary)] sm:px-5">
|
||||
<span class="icon-[lucide--megaphone] size-4" aria-hidden="true"></span>
|
||||
<span class="text-sm font-bold">{title}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="group relative min-w-0 flex-1 overflow-hidden"
|
||||
@mouseenter='paused = true; event.currentTarget.dispatchEvent(new CustomEvent("pause", { bubbles: true }))'
|
||||
@mouseleave='paused = false; event.currentTarget.dispatchEvent(new CustomEvent("resume", { bubbles: true }))'
|
||||
@focusin='paused = true'
|
||||
@focusout='paused = false'
|
||||
>
|
||||
<div
|
||||
class="wire-marquee-track flex w-max min-w-full items-center"
|
||||
class:wire-marquee-paused='paused'
|
||||
>
|
||||
{#each items as item}
|
||||
<a
|
||||
href='{item.href || "#"}'
|
||||
class="flex shrink-0 items-center gap-3 px-5 py-3 text-sm font-medium text-[var(--wire-color-text)] transition hover:bg-[var(--wire-color-primary-soft)] hover:text-[var(--wire-color-primary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--wire-color-focus)]"
|
||||
>
|
||||
<span
|
||||
class="size-2 shrink-0 rounded-full bg-[var(--wire-color-primary)]"
|
||||
class:bg-[var(--wire-color-danger)]='item.color === "danger"'
|
||||
class:bg-[var(--wire-color-warning)]='item.color === "warning"'
|
||||
class:bg-[var(--wire-color-success)]='item.color === "success"'
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<span>{item.label || item.title}</span>
|
||||
{#if item.meta}
|
||||
<span class="text-xs text-[var(--wire-color-text-muted)]">{item.meta}</span>
|
||||
{/if}
|
||||
</a>
|
||||
{:empty}
|
||||
<p class="px-5 py-3 text-sm text-[var(--wire-color-text-muted)]">{description || "No announcements available."}</p>
|
||||
{/each}
|
||||
|
||||
{#if items.length > 0}
|
||||
{#each items as item}
|
||||
<a
|
||||
href='{item.href || "#"}'
|
||||
aria-hidden="true"
|
||||
tabindex="-1"
|
||||
class="flex shrink-0 items-center gap-3 px-5 py-3 text-sm font-medium text-[var(--wire-color-text)]"
|
||||
>
|
||||
<span class="size-2 shrink-0 rounded-full bg-[var(--wire-color-primary)]" aria-hidden="true"></span>
|
||||
<span>{item.label || item.title}</span>
|
||||
</a>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
aria-label='{paused ? "Resume announcements" : "Pause announcements"}'
|
||||
class="flex shrink-0 items-center justify-center border-l border-[var(--wire-color-border)] px-4 text-[var(--wire-color-text-muted)] transition hover:bg-[var(--wire-color-surface-soft)] hover:text-[var(--wire-color-text)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--wire-color-focus)]"
|
||||
@click='paused = !paused; event.currentTarget.dispatchEvent(new CustomEvent(paused ? "pause" : "resume", { bubbles: true }))'
|
||||
>
|
||||
<span class="icon-[lucide--pause] size-4" data-show='!paused' aria-hidden="true"></span>
|
||||
<span class="icon-[lucide--play] size-4" data-show='paused' aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<slot></slot>
|
||||
</section>
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--search-box {class}"><span>{label}</span><input {...attrs} type="{type}" name="{name}" value="{value}" placeholder="{placeholder}" min="{min}" max="{max}" step="{step}" disabled="{disabled}" required="{required}" /></label>
|
||||
<form
|
||||
data-ui-component="SearchBox"
|
||||
role="search"
|
||||
class='w-full {class}'
|
||||
@submit='event.preventDefault(); event.currentTarget.dispatchEvent(new CustomEvent("search", { bubbles: true, detail: { value: query, name: name } }))'
|
||||
>
|
||||
<label
|
||||
class="mb-2 block text-sm font-semibold text-[var(--wire-color-text)]"
|
||||
class:sr-only='label === ""'
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
|
||||
<div class="relative flex items-center">
|
||||
<span
|
||||
class="icon-[lucide--search] pointer-events-none absolute left-4 size-5 text-[var(--wire-color-input-placeholder)]"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
|
||||
<input
|
||||
name='{name}'
|
||||
type='{type}'
|
||||
value='{query}'
|
||||
placeholder='{placeholder}'
|
||||
min='{min}'
|
||||
max='{max}'
|
||||
step='{step}'
|
||||
disabled='{disabled}'
|
||||
required='{required}'
|
||||
autocomplete="off"
|
||||
class="w-full rounded-xl border border-[var(--wire-color-input-border)] bg-[var(--wire-color-input-background)] pl-12 pr-24 text-[var(--wire-color-input-text)] outline-none transition placeholder:text-[var(--wire-color-input-placeholder)] hover:border-[var(--wire-color-input-border-hover)] focus:border-[var(--wire-color-input-border-focus)] focus:ring-2 focus:ring-[var(--wire-color-focus)] disabled:cursor-not-allowed disabled:opacity-60"
|
||||
class:h-10='size === "sm"'
|
||||
class:h-12='size === "default" || size === "md"'
|
||||
class:h-14='size === "lg"'
|
||||
@input='query = event.target.value'
|
||||
@change='query = event.target.value'
|
||||
/>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Clear search"
|
||||
data-show='query.length > 0 && !disabled'
|
||||
class="absolute right-12 inline-flex size-8 items-center justify-center rounded-lg text-[var(--wire-color-text-muted)] transition hover:bg-[var(--wire-color-surface-soft)] hover:text-[var(--wire-color-text)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)]"
|
||||
@click='query = ""; event.currentTarget.parentElement.querySelector("input")?.focus(); event.currentTarget.dispatchEvent(new CustomEvent("clear", { bubbles: true, detail: { value: "", name: name } }))'
|
||||
>
|
||||
<span class="icon-[lucide--x] size-4" aria-hidden="true"></span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
aria-label='{label || "Search"}'
|
||||
disabled='{disabled}'
|
||||
class="absolute right-2 inline-flex size-9 items-center justify-center rounded-lg bg-[var(--wire-color-primary)] text-[var(--wire-color-on-primary)] transition hover:bg-[var(--wire-color-primary-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)] disabled:cursor-not-allowed disabled:opacity-60"
|
||||
>
|
||||
<span class="icon-[lucide--arrow-right] size-4" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
<nav class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--tabs wire-next--{orientation} {class}" aria-label="{label}">
|
||||
{#each items as item}<a href="{item.href}" aria-current="{item.value === active ? 'page' : ''}">{item.label}</a>{/each}
|
||||
<slot />
|
||||
</nav>
|
||||
<section
|
||||
data-ui-component="Tabs"
|
||||
class='w-full {class}'
|
||||
class:flex='orientation === "vertical"'
|
||||
class:items-start='orientation === "vertical"'
|
||||
class:gap-6='orientation === "vertical"'
|
||||
>
|
||||
<div
|
||||
role="tablist"
|
||||
aria-label='{label}'
|
||||
aria-orientation='{orientation}'
|
||||
class="flex min-w-0 gap-1 overflow-x-auto rounded-xl border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-soft)] p-1"
|
||||
class:flex-col='orientation === "vertical"'
|
||||
class:w-56='orientation === "vertical"'
|
||||
class:shrink-0='orientation === "vertical"'
|
||||
>
|
||||
{#each items as item, index}
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
id='tab-{item.value || item.id || index}'
|
||||
aria-selected='{activeValue === (item.value || item.id || String(index))}'
|
||||
aria-controls='panel-{item.value || item.id || index}'
|
||||
tabindex='{activeValue === (item.value || item.id || String(index)) ? "0" : "-1"}'
|
||||
disabled='{item.disabled || false}'
|
||||
class="inline-flex min-w-max flex-1 items-center justify-center gap-2 rounded-lg px-4 py-2.5 text-sm font-semibold outline-none transition disabled:cursor-not-allowed disabled:opacity-50"
|
||||
class:bg-[var(--wire-color-surface-raised)]='activeValue === (item.value || item.id || String(index))'
|
||||
class:text-[var(--wire-color-primary)]='activeValue === (item.value || item.id || String(index))'
|
||||
class:shadow-sm='activeValue === (item.value || item.id || String(index))'
|
||||
class:text-[var(--wire-color-text-muted)]='activeValue !== (item.value || item.id || String(index))'
|
||||
class:hover:text-[var(--wire-color-text)]='activeValue !== (item.value || item.id || String(index))'
|
||||
class:justify-start='orientation === "vertical"'
|
||||
class:px-3='size === "sm"'
|
||||
class:py-2='size === "sm"'
|
||||
class:px-5='size === "lg"'
|
||||
class:py-3='size === "lg"'
|
||||
@click='activeValue = item.value || item.id || String(index); event.currentTarget.dispatchEvent(new CustomEvent("change", { bubbles: true, detail: { item: item, index: index, value: activeValue } })); event.currentTarget.dispatchEvent(new CustomEvent("select", { bubbles: true, detail: { item: item, index: index, value: activeValue } }))'
|
||||
>
|
||||
{#if item.icon}
|
||||
<span class='{item.icon + " size-4"}' aria-hidden="true"></span>
|
||||
{/if}
|
||||
<span>{item.label || item.title}</span>
|
||||
{#if item.badge}
|
||||
<span class="rounded-full bg-[var(--wire-color-primary-soft)] px-2 py-0.5 text-xs text-[var(--wire-color-primary)]">{item.badge}</span>
|
||||
{/if}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<div class="min-w-0 flex-1 pt-4" class:pt-0='orientation === "vertical"'>
|
||||
{#each items as item, index}
|
||||
<div
|
||||
role="tabpanel"
|
||||
id='panel-{item.value || item.id || index}'
|
||||
aria-labelledby='tab-{item.value || item.id || index}'
|
||||
tabindex="0"
|
||||
data-show='activeValue === (item.value || item.id || String(index))'
|
||||
class="rounded-xl outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)]"
|
||||
>
|
||||
{#if item.title && item.title !== item.label}
|
||||
<h3 class="text-lg font-bold text-[var(--wire-color-text)]">{item.title}</h3>
|
||||
{/if}
|
||||
{#if item.description}
|
||||
<p class="mt-2 leading-7 text-[var(--wire-color-text-muted)]">{item.description}</p>
|
||||
{/if}
|
||||
{#if item.content}
|
||||
<div class="mt-4 text-[var(--wire-color-text)]">{item.content}</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<slot></slot>
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--timeline wire-next--variant-{variant} {class}">
|
||||
{#if title}<strong>{title}</strong>{/if}
|
||||
{#if description}<p>{description}</p>{/if}
|
||||
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||
<slot />
|
||||
<section
|
||||
data-ui-component="Timeline"
|
||||
aria-label='{title}'
|
||||
class='w-full {class}'
|
||||
>
|
||||
{#if title || description}
|
||||
<header class="mb-6">
|
||||
{#if title}
|
||||
<h3 class="text-xl font-bold text-[var(--wire-color-text)]">{title}</h3>
|
||||
{/if}
|
||||
{#if description}
|
||||
<p class="mt-2 max-w-2xl leading-7 text-[var(--wire-color-text-muted)]">{description}</p>
|
||||
{/if}
|
||||
</header>
|
||||
{/if}
|
||||
|
||||
<ol class="relative ml-4 border-l border-[var(--wire-color-border)]">
|
||||
{#each items as item, index}
|
||||
<li
|
||||
class="relative pb-8 pl-8 last:pb-0"
|
||||
@click='event.currentTarget.dispatchEvent(new CustomEvent("select", { bubbles: true, detail: { item: item, index: index } }))'
|
||||
>
|
||||
<span
|
||||
class="absolute -left-[1.05rem] top-0 flex size-8 items-center justify-center rounded-full border-4 border-[var(--wire-color-background)] bg-[var(--wire-color-primary)] text-[var(--wire-color-on-primary)] shadow-sm"
|
||||
class:bg-[var(--wire-color-success)]='item.status === "complete" || item.status === "success"'
|
||||
class:bg-[var(--wire-color-warning)]='item.status === "warning" || item.status === "pending"'
|
||||
class:bg-[var(--wire-color-danger)]='item.status === "danger" || item.status === "failed"'
|
||||
>
|
||||
<span class='{item.icon || "icon-[lucide--circle]"}' aria-hidden="true"></span>
|
||||
</span>
|
||||
|
||||
<article
|
||||
class="rounded-2xl border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] p-5 shadow-sm"
|
||||
class:border-transparent='variant === "minimal"'
|
||||
class:bg-transparent='variant === "minimal"'
|
||||
class:p-0='variant === "minimal"'
|
||||
class:shadow-none='variant === "minimal"'
|
||||
>
|
||||
<div class="flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div>
|
||||
<h4 class="font-bold text-[var(--wire-color-text)]">{item.title || item.label}</h4>
|
||||
{#if item.subtitle}
|
||||
<p class="mt-1 text-sm font-medium text-[var(--wire-color-primary)]">{item.subtitle}</p>
|
||||
{/if}
|
||||
</div>
|
||||
{#if item.date || item.meta}
|
||||
<time class="shrink-0 text-sm text-[var(--wire-color-text-muted)]">{item.date || item.meta}</time>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if item.description}
|
||||
<p class="mt-3 text-sm leading-6 text-[var(--wire-color-text-muted)]">{item.description}</p>
|
||||
{/if}
|
||||
|
||||
{#if item.href}
|
||||
<a href='{item.href}' class="mt-4 inline-flex items-center gap-2 text-sm font-semibold text-[var(--wire-color-primary)] hover:text-[var(--wire-color-primary-hover)]">
|
||||
<span>{item.actionLabel || "View details"}</span>
|
||||
<span class="icon-[lucide--arrow-right] size-4" aria-hidden="true"></span>
|
||||
</a>
|
||||
{/if}
|
||||
</article>
|
||||
</li>
|
||||
{:empty}
|
||||
<li class="pl-8 text-sm text-[var(--wire-color-text-muted)]">No timeline items available.</li>
|
||||
{/each}
|
||||
</ol>
|
||||
|
||||
<slot></slot>
|
||||
</section>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,69 @@ component Typography {
|
||||
maxWidth = "xl"
|
||||
class = ""
|
||||
}
|
||||
|
||||
view {
|
||||
<article class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--typography wire-next--gap-{gap} wire-next--columns-{columns} wire-next--max-{maxWidth} {class}"><slot /></article>
|
||||
<div
|
||||
data-ui-component="Typography"
|
||||
class='wire-typography text-[var(--wire-color-text)] {class}'
|
||||
class:max-w-3xl='maxWidth === "md"'
|
||||
class:max-w-5xl='maxWidth === "lg"'
|
||||
class:max-w-7xl='maxWidth === "xl"'
|
||||
class:max-w-none='maxWidth === "full"'
|
||||
class:text-sm='size === "sm"'
|
||||
class:text-base='size === "default" || size === "md"'
|
||||
class:text-lg='size === "lg"'
|
||||
class:columns-1='columns === 1'
|
||||
class:md:columns-2='columns === 2'
|
||||
class:lg:columns-3='columns === 3'
|
||||
class:gap-4='gap === "sm"'
|
||||
class:gap-8='gap === "md"'
|
||||
class:gap-12='gap === "lg"'
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
}
|
||||
|
||||
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; }
|
||||
}
|
||||
}
|
||||
|
||||
+222
-132
@@ -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 {
|
||||
<section
|
||||
<div
|
||||
{...attrs}
|
||||
class="wire-next wire-next--card {class}"
|
||||
data-size="{size}"
|
||||
data-color="{color}"
|
||||
data-variant="{variant}"
|
||||
data-layout="{layout}"
|
||||
data-align="{align}"
|
||||
data-hover="{hover}"
|
||||
data-image-position="{imagePosition}"
|
||||
data-group="{items.length > 0}"
|
||||
aria-label="{ariaLabel || title}"
|
||||
data-ui-component="Card"
|
||||
data-wrn-card
|
||||
data-size='{size}'
|
||||
data-color='{color}'
|
||||
data-variant='{variant}'
|
||||
data-layout='{layout}'
|
||||
data-hover='{hover}'
|
||||
data-align='{align}'
|
||||
class='wire-next wire-next--card wire-next--color-{color} wire-next--size-{size} wire-next--variant-{variant} {class}'
|
||||
>
|
||||
{#if items.length > 0}
|
||||
<div class="wire-next__card-group">
|
||||
{#each items as item}
|
||||
<article class="wire-next__card-panel">
|
||||
{#if item.imageSrc}
|
||||
{#each items as item, itemIndex}
|
||||
<article
|
||||
class="wire-next__card-panel"
|
||||
aria-label='{item.ariaLabel || item.title || item.label || "Card item"}'
|
||||
data-index='{itemIndex}'
|
||||
>
|
||||
{#if item.imageSrc || item.image}
|
||||
<div class="wire-next__card-media">
|
||||
<img src="{item.imageSrc}" alt="{item.imageAlt || ''}" loading="lazy" />
|
||||
<img
|
||||
src='{item.imageSrc || item.image}'
|
||||
alt='{item.imageAlt || item.alt || ""}'
|
||||
loading='{item.loading || "lazy"}'
|
||||
decoding="async"
|
||||
@load='event.currentTarget.dispatchEvent(new CustomEvent("load", { bubbles: true, detail: { item: item, index: itemIndex } }))'
|
||||
@error='event.currentTarget.dispatchEvent(new CustomEvent("error", { bubbles: true, detail: { item: item, index: itemIndex } }))'
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="wire-next__card-body">
|
||||
{#if item.title}<h3>{item.title}</h3>{/if}
|
||||
{#if item.description}<p>{item.description}</p>{/if}
|
||||
|
||||
<div class="wire-next__card-content">
|
||||
{#if item.title || item.label}
|
||||
<h3>{item.title || item.label}</h3>
|
||||
{/if}
|
||||
{#if item.subtitle}
|
||||
<p class="wire-next__card-subtitle">{item.subtitle}</p>
|
||||
{/if}
|
||||
{#if item.description}
|
||||
<p class="wire-next__card-description">{item.description}</p>
|
||||
{/if}
|
||||
{#if item.actionLabel || item.href}
|
||||
<a
|
||||
href='{item.actionHref || item.href || "#"}'
|
||||
class="wire-next__card-action"
|
||||
@click='event.currentTarget.dispatchEvent(new CustomEvent("action", { bubbles: true, detail: { item: item, index: itemIndex } }))'
|
||||
>
|
||||
<span>{item.actionLabel || "Learn more"}</span>
|
||||
<span class="icon-[lucide--arrow-right]" aria-hidden="true"></span>
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
{#if item.footer}<footer class="wire-next__card-footer">{item.footer}</footer>{/if}
|
||||
</article>
|
||||
{/each}
|
||||
</div>
|
||||
{:else if visible}
|
||||
<article class="wire-next__card-panel">
|
||||
{#if imagePosition === "overlay" && imageSrc}
|
||||
<div class="wire-next__card-media wire-next__card-media--overlay">
|
||||
{:else}
|
||||
<article
|
||||
class="wire-next__card-panel"
|
||||
aria-label='{ariaLabel || title || "Card"}'
|
||||
hidden='{dismissed}'
|
||||
>
|
||||
{#if imageSrc && imagePosition === "overlay"}
|
||||
<div class="wire-next__card-overlay">
|
||||
<img
|
||||
src="{imageSrc}"
|
||||
alt="{imageAlt}"
|
||||
src='{imageSrc}'
|
||||
alt='{imageAlt}'
|
||||
loading="lazy"
|
||||
@load="$emit('load', { src: imageSrc })"
|
||||
@error="$emit('error', { src: imageSrc })"
|
||||
decoding="async"
|
||||
@load='event.currentTarget.dispatchEvent(new CustomEvent("load", { bubbles: true, detail: { src: imageSrc } }))'
|
||||
@error='event.currentTarget.dispatchEvent(new CustomEvent("error", { bubbles: true, detail: { src: imageSrc } }))'
|
||||
/>
|
||||
<div class="wire-next__card-overlay">
|
||||
{#if title}<h3>{title}</h3>{/if}
|
||||
{#if subtitle}<span class="wire-next__card-subtitle">{subtitle}</span>{/if}
|
||||
{#if description}<p>{description}</p>{/if}
|
||||
{#if footer}<small>{footer}</small>{/if}
|
||||
</div>
|
||||
<div class="wire-next__card-overlay-shade" aria-hidden="true"></div>
|
||||
</div>
|
||||
{:else}
|
||||
{#if header || headerActions.length > 0 || dismissible}
|
||||
{/if}
|
||||
|
||||
{#if imageSrc && (imagePosition === "top" || imagePosition === "left")}
|
||||
<div class="wire-next__card-media wire-next__card-media--{imagePosition}">
|
||||
<img
|
||||
src='{imageSrc}'
|
||||
alt='{imageAlt}'
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
@load='event.currentTarget.dispatchEvent(new CustomEvent("load", { bubbles: true, detail: { src: imageSrc } }))'
|
||||
@error='event.currentTarget.dispatchEvent(new CustomEvent("error", { bubbles: true, detail: { src: imageSrc } }))'
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="wire-next__card-content">
|
||||
{#if header || title || subtitle || headerActions.length > 0 || dismissible}
|
||||
<header class="wire-next__card-header">
|
||||
<span>{header}</span>
|
||||
<div class="wire-next__card-heading">
|
||||
{#if header}
|
||||
<p class="wire-next__card-eyebrow">{header}</p>
|
||||
{/if}
|
||||
{#if title}
|
||||
<h3>{title}</h3>
|
||||
{/if}
|
||||
{#if subtitle}
|
||||
<p class="wire-next__card-subtitle">{subtitle}</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if headerActions.length > 0 || dismissible}
|
||||
<span class="wire-next__card-header-actions">
|
||||
{#each headerActions as action, index}
|
||||
<div class="wire-next__card-header-actions">
|
||||
{#each headerActions as headerAction, actionIndex}
|
||||
<button
|
||||
type="button"
|
||||
aria-label="{action.ariaLabel || action.label}"
|
||||
title="{action.label}"
|
||||
@click="chooseAction(action, index)"
|
||||
aria-label='{headerAction.ariaLabel || headerAction.label || "Card action"}'
|
||||
@click='dispatchCardHeaderAction(event, headerAction, actionIndex)'
|
||||
>
|
||||
{#if action.icon}<span class="{action.icon}" aria-hidden="true"></span>{/if}
|
||||
{#if !action.icon}<span>{action.label}</span>{/if}
|
||||
{#if headerAction.icon}
|
||||
<span class='{headerAction.icon}' aria-hidden="true"></span>
|
||||
{/if}
|
||||
{#if headerAction.label && !headerAction.icon}
|
||||
<span>{headerAction.label}</span>
|
||||
{/if}
|
||||
</button>
|
||||
{/each}
|
||||
|
||||
{#if dismissible}
|
||||
<button type="button" aria-label="Close card" @click="dismissCard(event)">
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Dismiss card"
|
||||
@click='dismissCard(event)'
|
||||
>
|
||||
<span class="icon-[lucide--x]" aria-hidden="true"></span>
|
||||
</button>
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
</header>
|
||||
{/if}
|
||||
|
||||
{#if navigation.length > 0}
|
||||
<nav class="wire-next__card-navigation" aria-label="{ariaLabel || title}">
|
||||
<div class="wire-next__card-tabs">
|
||||
{#each navigation as item, index}
|
||||
<button
|
||||
type="button"
|
||||
data-active="{selectedNav === (item.value || item.label)}"
|
||||
aria-current="{selectedNav === (item.value || item.label) ? 'page' : ''}"
|
||||
@click="chooseNavigation(item, index)"
|
||||
>
|
||||
{item.label}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<nav aria-label='{ariaLabel || title || "Card navigation"}' class="wire-next__card-navigation">
|
||||
{#if mobileNavigation}
|
||||
<select
|
||||
class="wire-next__card-navigation-select"
|
||||
aria-label="{ariaLabel || title}"
|
||||
value="{selectedNav}"
|
||||
@change="chooseMobileNavigation(event)"
|
||||
aria-label='{ariaLabel || title || "Card navigation"}'
|
||||
@change='dispatchCardNavigationValue(event)'
|
||||
>
|
||||
{#each navigation as item}
|
||||
{#each navigation as navItem}
|
||||
<option
|
||||
value="{item.value || item.label}"
|
||||
selected="{selectedNav === (item.value || item.label)}"
|
||||
value='{navItem.value || navItem.href || navItem.label}'
|
||||
selected='{activeNav === navItem.value || activeNav === navItem.href}'
|
||||
>
|
||||
{item.label}
|
||||
{navItem.label}
|
||||
</option>
|
||||
{/each}
|
||||
</select>
|
||||
{/if}
|
||||
|
||||
<div class="wire-next__card-tabs" data-mobile-navigation='{mobileNavigation}'>
|
||||
{#each navigation as navItem, navIndex}
|
||||
<button
|
||||
type="button"
|
||||
aria-pressed='{activeNav === navItem.value || activeNav === navItem.href}'
|
||||
@click='dispatchCardNavigation(event, navItem, navIndex)'
|
||||
>
|
||||
{#if navItem.icon}
|
||||
<span class='{navItem.icon}' aria-hidden="true"></span>
|
||||
{/if}
|
||||
<span>{navItem.label}</span>
|
||||
{#if navItem.badge}
|
||||
<span class="wire-next__card-tab-badge">{navItem.badge}</span>
|
||||
{/if}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
</nav>
|
||||
{/if}
|
||||
|
||||
{#if imageSrc && imagePosition !== "bottom"}
|
||||
<div class="wire-next__card-media">
|
||||
<img
|
||||
src="{imageSrc}"
|
||||
alt="{imageAlt}"
|
||||
loading="lazy"
|
||||
@load="$emit('load', { src: imageSrc })"
|
||||
@error="$emit('error', { src: imageSrc })"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if alertTitle || alertDescription}
|
||||
<aside class="wire-next__card-alert" role="status">
|
||||
{#if alertTitle}<strong>{alertTitle}</strong>{/if}
|
||||
{#if alertDescription}<span>{alertDescription}</span>{/if}
|
||||
</aside>
|
||||
<div class="wire-next__card-alert" role="status">
|
||||
{#if alertTitle}
|
||||
<strong>{alertTitle}</strong>
|
||||
{/if}
|
||||
{#if alertDescription}
|
||||
<p>{alertDescription}</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="wire-next__card-body"
|
||||
data-scrollable="{scrollable}"
|
||||
style="--wire-card-max-height: {maxHeight}"
|
||||
data-scrollable='{scrollable}'
|
||||
style='max-height: {scrollable ? maxHeight : "none"};'
|
||||
>
|
||||
{#if empty}
|
||||
<div class="wire-next__card-empty">
|
||||
<span class="{emptyIcon}" aria-hidden="true"></span>
|
||||
<strong>{emptyTitle}</strong>
|
||||
<span class='{emptyIcon}' aria-hidden="true"></span>
|
||||
<p>{emptyTitle}</p>
|
||||
</div>
|
||||
{:else}
|
||||
{#if title}<h3>{title}</h3>{/if}
|
||||
{#if subtitle}<span class="wire-next__card-subtitle">{subtitle}</span>{/if}
|
||||
{#if description}<p>{description}</p>{/if}
|
||||
<slot />
|
||||
{#if actionLabel}
|
||||
<a
|
||||
class="wire-next__card-action"
|
||||
href="{actionHref || '#'}"
|
||||
@click="$emit('action', { label: actionLabel, href: actionHref })"
|
||||
>
|
||||
{actionLabel}<span class="icon-[lucide--chevron-right]" aria-hidden="true"></span>
|
||||
</a>
|
||||
{#if description}
|
||||
<p class="wire-next__card-description">{description}</p>
|
||||
{/if}
|
||||
<slot></slot>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if footer}<footer class="wire-next__card-footer">{footer}</footer>{/if}
|
||||
|
||||
{#if imageSrc && imagePosition === "bottom"}
|
||||
<div class="wire-next__card-media">
|
||||
<img
|
||||
src="{imageSrc}"
|
||||
alt="{imageAlt}"
|
||||
loading="lazy"
|
||||
@load="$emit('load', { src: imageSrc })"
|
||||
@error="$emit('error', { src: imageSrc })"
|
||||
/>
|
||||
</div>
|
||||
{#if footer || actionLabel}
|
||||
<footer class="wire-next__card-footer">
|
||||
{#if footer}
|
||||
<span>{footer}</span>
|
||||
{/if}
|
||||
{#if actionLabel}
|
||||
<a
|
||||
href='{actionHref || "#"}'
|
||||
class="wire-next__card-action"
|
||||
@click='event.currentTarget.dispatchEvent(new CustomEvent("action", { bubbles: true, detail: { href: actionHref, label: actionLabel } }))'
|
||||
>
|
||||
<span>{actionLabel}</span>
|
||||
<span class="icon-[lucide--arrow-right]" aria-hidden="true"></span>
|
||||
</a>
|
||||
{/if}
|
||||
</footer>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if imageSrc && (imagePosition === "bottom" || imagePosition === "right")}
|
||||
<div class="wire-next__card-media wire-next__card-media--{imagePosition}">
|
||||
<img
|
||||
src='{imageSrc}'
|
||||
alt='{imageAlt}'
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
@load='event.currentTarget.dispatchEvent(new CustomEvent("load", { bubbles: true, detail: { src: imageSrc } }))'
|
||||
@error='event.currentTarget.dispatchEvent(new CustomEvent("error", { bubbles: true, detail: { src: imageSrc } }))'
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</article>
|
||||
{/if}
|
||||
</section>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,40 @@ component Container {
|
||||
maxWidth = "xl"
|
||||
class = ""
|
||||
}
|
||||
|
||||
view {
|
||||
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--container wire-next--gap-{gap} wire-next--columns-{columns} wire-next--max-{maxWidth} {class}"><slot /></div>
|
||||
<div
|
||||
data-ui-component="Container"
|
||||
data-size='{size}'
|
||||
data-color='{color}'
|
||||
data-columns='{columns}'
|
||||
data-gap='{gap}'
|
||||
data-max-width='{maxWidth}'
|
||||
class='mx-auto w-full {class}'
|
||||
class:max-w-3xl='maxWidth === "md"'
|
||||
class:max-w-5xl='maxWidth === "lg"'
|
||||
class:max-w-7xl='maxWidth === "xl" || maxWidth === "wide"'
|
||||
class:max-w-screen-2xl='maxWidth === "2xl"'
|
||||
class:max-w-none='maxWidth === "full"'
|
||||
class:px-4='size === "compact" || size === "default"'
|
||||
class:px-5='size === "comfortable"'
|
||||
class:px-6='size === "spacious"'
|
||||
class:sm:px-6='size !== "compact"'
|
||||
class:lg:px-8='size === "default" || size === "comfortable" || size === "spacious"'
|
||||
class:grid='columns > 1'
|
||||
class:grid-cols-1='columns > 1'
|
||||
class:sm:grid-cols-2='columns === 2 || columns === 3 || columns === 4 || columns === 5 || columns === 6'
|
||||
class:lg:grid-cols-3='columns === 3'
|
||||
class:lg:grid-cols-4='columns === 4'
|
||||
class:lg:grid-cols-5='columns === 5'
|
||||
class:lg:grid-cols-6='columns === 6'
|
||||
class:gap-2='gap === "xs"'
|
||||
class:gap-3='gap === "sm"'
|
||||
class:gap-5='gap === "md"'
|
||||
class:gap-8='gap === "lg"'
|
||||
class:gap-10='gap === "xl"'
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,64 @@ component Divider {
|
||||
orientation = "horizontal"
|
||||
class = ""
|
||||
}
|
||||
|
||||
view {
|
||||
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--divider wire-next--divider-{orientation} {class}" role="separator" aria-orientation="{orientation}">{#if label}<span>{label}</span>{/if}</div>
|
||||
<div
|
||||
{...attrs}
|
||||
data-ui-component="Divider"
|
||||
data-size='{size}'
|
||||
data-color='{color}'
|
||||
data-orientation='{orientation}'
|
||||
class='w-full {class}'
|
||||
class:h-full='orientation === "vertical"'
|
||||
class:w-auto='orientation === "vertical"'
|
||||
>
|
||||
{#if orientation === "vertical"}
|
||||
<div
|
||||
role="separator"
|
||||
aria-orientation="vertical"
|
||||
class="mx-3 h-full min-h-6 border-l border-[var(--wire-color-border)]"
|
||||
class:border-l-2='size === "lg"'
|
||||
class:border-[var(--wire-color-primary)]='color === "primary"'
|
||||
class:border-[var(--wire-color-secondary)]='color === "secondary"'
|
||||
class:border-[var(--wire-color-success)]='color === "success"'
|
||||
class:border-[var(--wire-color-warning)]='color === "warning"'
|
||||
class:border-[var(--wire-color-danger)]='color === "danger"'
|
||||
></div>
|
||||
{:else}
|
||||
<div
|
||||
role="separator"
|
||||
aria-orientation="horizontal"
|
||||
class="flex w-full items-center gap-4"
|
||||
>
|
||||
<span
|
||||
class="h-px flex-1 bg-[var(--wire-color-border)]"
|
||||
class:h-0.5='size === "lg"'
|
||||
class:bg-[var(--wire-color-primary)]='color === "primary" && label !== ""'
|
||||
class:bg-[var(--wire-color-secondary)]='color === "secondary" && label !== ""'
|
||||
class:bg-[var(--wire-color-success)]='color === "success" && label !== ""'
|
||||
class:bg-[var(--wire-color-warning)]='color === "warning" && label !== ""'
|
||||
class:bg-[var(--wire-color-danger)]='color === "danger" && label !== ""'
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
|
||||
{#if label}
|
||||
<span class="shrink-0 text-xs font-bold uppercase tracking-[0.16em] text-[var(--wire-color-text-muted)]">
|
||||
{label}
|
||||
</span>
|
||||
<span
|
||||
class="h-px flex-1 bg-[var(--wire-color-border)]"
|
||||
class:h-0.5='size === "lg"'
|
||||
class:bg-[var(--wire-color-primary)]='color === "primary"'
|
||||
class:bg-[var(--wire-color-secondary)]='color === "secondary"'
|
||||
class:bg-[var(--wire-color-success)]='color === "success"'
|
||||
class:bg-[var(--wire-color-warning)]='color === "warning"'
|
||||
class:bg-[var(--wire-color-danger)]='color === "danger"'
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,34 @@ component Grid {
|
||||
maxWidth = "xl"
|
||||
class = ""
|
||||
}
|
||||
|
||||
view {
|
||||
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--grid wire-next--gap-{gap} wire-next--columns-{columns} wire-next--max-{maxWidth} {class}"><slot /></div>
|
||||
<div
|
||||
data-ui-component="Grid"
|
||||
data-size='{size}'
|
||||
data-color='{color}'
|
||||
data-columns='{columns}'
|
||||
data-gap='{gap}'
|
||||
class='grid w-full grid-cols-1 {class}'
|
||||
class:max-w-3xl='maxWidth === "md"'
|
||||
class:max-w-5xl='maxWidth === "lg"'
|
||||
class:max-w-7xl='maxWidth === "xl"'
|
||||
class:max-w-screen-2xl='maxWidth === "2xl"'
|
||||
class:max-w-none='maxWidth === "full"'
|
||||
class:sm:grid-cols-2='columns >= 2'
|
||||
class:lg:grid-cols-3='columns === 3'
|
||||
class:lg:grid-cols-4='columns === 4'
|
||||
class:lg:grid-cols-5='columns === 5'
|
||||
class:lg:grid-cols-6='columns === 6'
|
||||
class:gap-2='gap === "xs"'
|
||||
class:gap-3='gap === "sm"'
|
||||
class:gap-5='gap === "md"'
|
||||
class:gap-8='gap === "lg"'
|
||||
class:gap-10='gap === "xl"'
|
||||
class:items-start='size === "compact"'
|
||||
class:items-stretch='size !== "compact"'
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user