release: WRNexusJS 0.5.0

This commit is contained in:
2026-07-29 12:51:10 +05:30
parent 76c768099d
commit 6afe32f63f
456 changed files with 40879 additions and 8850 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ai",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/authz",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/authz — part of the WrNexus framework.",
"license": "MIT",
+13 -13
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/cli",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/cli — part of the WrNexus framework.",
"license": "MIT",
@@ -28,18 +28,18 @@
"wrnexus": "./dist/index.js"
},
"dependencies": {
"@wrnexus/core": "^0.4.0",
"@wrnexus/router": "^0.4.0",
"@wrnexus/csr": "^0.4.0",
"@wrnexus/compiler": "^0.4.0",
"@wrnexus/styles": "^0.4.0",
"@wrnexus/dev-server": "^0.4.0",
"@wrnexus/ui": "^0.4.0",
"@wrnexus/validation": "^0.4.0",
"@wrnexus/i18n": "^0.4.0",
"@wrnexus/db": "^0.4.0",
"@wrnexus/plugin": "^0.4.0",
"@wrnexus/syntax": "^0.4.0"
"@wrnexus/core": "^0.5.0",
"@wrnexus/router": "^0.5.0",
"@wrnexus/csr": "^0.5.0",
"@wrnexus/compiler": "^0.5.0",
"@wrnexus/styles": "^0.5.0",
"@wrnexus/dev-server": "^0.5.0",
"@wrnexus/ui": "^0.5.0",
"@wrnexus/validation": "^0.5.0",
"@wrnexus/i18n": "^0.5.0",
"@wrnexus/db": "^0.5.0",
"@wrnexus/plugin": "^0.5.0",
"@wrnexus/syntax": "^0.5.0"
},
"files": [
"dist"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/compiler",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/compiler — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/syntax": "^0.4.0"
"@wrnexus/syntax": "^0.5.0"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/core",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/core — part of the WrNexus framework.",
"license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/csr",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/csr — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.4.0"
"@wrnexus/core": "^0.5.0"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/db",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/db — part of the WrNexus framework.",
"license": "MIT",
+15 -15
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/dev-server",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/dev-server — part of the WrNexus framework.",
"license": "MIT",
@@ -25,20 +25,20 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.4.0",
"@wrnexus/dev-toolbar": "^0.4.0",
"@wrnexus/router": "^0.4.0",
"@wrnexus/ssr": "^0.4.0",
"@wrnexus/csr": "^0.4.0",
"@wrnexus/compiler": "^0.4.0",
"@wrnexus/styles": "^0.4.0",
"@wrnexus/ui": "^0.4.0",
"@wrnexus/validation": "^0.4.0",
"@wrnexus/i18n": "^0.4.0",
"@wrnexus/db": "^0.4.0",
"@wrnexus/pubsub": "^0.4.0",
"@wrnexus/uploader": "^0.4.0",
"@wrnexus/plugin": "^0.4.0"
"@wrnexus/core": "^0.5.0",
"@wrnexus/dev-toolbar": "^0.5.0",
"@wrnexus/router": "^0.5.0",
"@wrnexus/ssr": "^0.5.0",
"@wrnexus/csr": "^0.5.0",
"@wrnexus/compiler": "^0.5.0",
"@wrnexus/styles": "^0.5.0",
"@wrnexus/ui": "^0.5.0",
"@wrnexus/validation": "^0.5.0",
"@wrnexus/i18n": "^0.5.0",
"@wrnexus/db": "^0.5.0",
"@wrnexus/pubsub": "^0.5.0",
"@wrnexus/uploader": "^0.5.0",
"@wrnexus/plugin": "^0.5.0"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/dev-toolbar",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/dev-toolbar — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/encryption",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/encryption — part of the WrNexus framework.",
"license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/helpers",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.4.0"
"@wrnexus/core": "^0.5.0"
},
"files": [
"dist"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/i18n",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/i18n — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.4.0"
"@wrnexus/core": "^0.5.0"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/jwt",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/jwt — part of the WrNexus framework.",
"license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/mobile",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/mobile — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/native": "^0.4.0"
"@wrnexus/native": "^0.5.0"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/native",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/native — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/oauth",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/oauth — part of the WrNexus framework.",
"license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/plugin",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/plugin — part of the WrNexus framework.",
"license": "MIT",
@@ -33,7 +33,7 @@
}
},
"dependencies": {
"@wrnexus/syntax": "^0.4.0"
"@wrnexus/syntax": "^0.5.0"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/pubsub",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/pubsub — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/queue",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/queue — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/reactive",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/reactive — part of the WrNexus framework.",
"license": "MIT",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/router",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/router — part of the WrNexus framework.",
"license": "MIT",
@@ -21,8 +21,8 @@
}
},
"dependencies": {
"@wrnexus/compiler": "^0.4.0",
"@wrnexus/core": "^0.4.0"
"@wrnexus/compiler": "^0.5.0",
"@wrnexus/core": "^0.5.0"
},
"files": [
"dist"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ssr",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/ssr — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.4.0"
"@wrnexus/core": "^0.5.0"
},
"files": [
"dist"
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/styles",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/styles — part of the WrNexus framework.",
"license": "MIT",
@@ -21,9 +21,9 @@
}
},
"dependencies": {
"@wrnexus/uploader": "^0.4.0",
"@wrnexus/core": "^0.4.0",
"@wrnexus/plugin": "^0.4.0"
"@wrnexus/uploader": "^0.5.0",
"@wrnexus/core": "^0.5.0",
"@wrnexus/plugin": "^0.5.0"
},
"files": [
"dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/syntax",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/syntax — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/test",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/test — part of the WrNexus framework.",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/tracking",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/tracking — part of the WrNexus framework.",
"license": "MIT",
+99 -99
View File
@@ -29,7 +29,7 @@ Theme-aware, responsive copy markup component.
- Mount: `data-component="CopyMarkup"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Copy Markup"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "text"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Slots: None
- Events: None
- Events: `copy`, `success`, `error`
### InputNumber
@@ -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: None
- Events: `input`, `change`, `search`, `submit`, `clear`
### StrongPassword
@@ -72,9 +72,9 @@ Theme-aware, responsive strong password component.
Theme-aware, responsive toggle count component.
- Mount: `data-component="ToggleCount"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Toggle Count"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "text"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `variant: string = "segmented"`, `class: string = ""`, `name: string = "billing-cycle"`, `value: string = "monthly"`, `firstValue: string = "monthly"`, `firstLabel: string = "Monthly"`, `secondValue: string = "annual"`, `secondLabel: string = "Annual"`, `ariaLabel: string = "Billing frequency"`, `items: string = []`, `currency: string = "$"`, `suffix: string = ""`, `firstValueKey: string = "monthly"`, `secondValueKey: string = "annual"`, `emptyValue: string = ""`, `align: string = "end"`, `fullWidth: boolean = true`, `disabled: boolean = false`, `animate: boolean = true`, `animationDuration: number = 450`, `animationSteps: number = 18`
- Slots: None
- Events: None
- Events: `change`, `toggle`
### TogglePassword
@@ -92,52 +92,52 @@ Accessible password field with optional show and hide controls.
Theme-aware, responsive accordion component.
- Mount: `data-component="Accordion"`
- Props: `size: string = "default"`, `color: string = "primary"`, `items: string = []`, `multiple: boolean = false`, `class: string = ""`
- Slots: `default`
- Events: None
- Props: `size: string = "default"`, `color: string = "primary"`, `variant: string = "default"`, `class: string = ""`, `id: string = "accordion"`, `items: string = []`, `defaultOpen: string = []`, `multiple: boolean = false`, `alwaysOpen: boolean = false`, `disabled: boolean = false`, `indicator: string = "plus"`, `indicatorPosition: string = "start"`, `showIndicator: boolean = true`, `bordered: boolean = false`, `separated: boolean = false`, `flush: boolean = false`, `contentItalic: boolean = false`
- Slots: None
- Events: `change`, `open`, `close`
### Alert
Theme-aware, responsive alert component.
- Mount: `data-component="Alert"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Alert"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Props: `size: string = "default"`, `color: string = "info"`, `variant: string = "soft"`, `class: string = ""`, `radius: string = "md"`, `shadow: string = "sm"`, `title: string = "Alert"`, `description: string = ""`, `items: string = []`, `actions: string = []`, `showIcon: boolean = false`, `icon: string = ""`, `dismissible: boolean = false`, `dismissLabel: string = "Dismiss alert"`, `role: string = "alert"`, `live: string = "polite"`, `linkLabel: string = ""`, `linkHref: string = ""`, `actionLabel: string = ""`, `actionHref: string = ""`, `compact: boolean = false`
- Slots: None
- Events: `dismiss`, `action`
### Avatar
Theme-aware, responsive avatar component.
- Mount: `data-component="Avatar"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Avatar"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Props: `src: string = ""`, `alt: string = ""`, `initials: string = ""`, `size: string = "md"`, `color: string = "primary"`, `variant: string = "solid"`, `shape: string = "circle"`, `status: string = ""`, `statusLabel: string = ""`, `statusPosition: string = "bottom"`, `badge: string = ""`, `badgeIcon: string = ""`, `badgeLabel: string = ""`, `tooltip: string = ""`, `name: string = ""`, `description: string = ""`, `loading: string = "lazy"`, `class: string = ""`
- Slots: None
- Events: `load`, `error`, `click`
### AvatarGroup
Theme-aware, responsive avatar group component.
- Mount: `data-component="AvatarGroup"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Avatar Group"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Props: `items: string = []`, `size: string = "md"`, `color: string = "primary"`, `variant: string = "solid"`, `shape: string = "circle"`, `layout: string = "stack"`, `maxVisible: number = 4`, `columns: number = 3`, `borderColor: string = ""`, `showTooltips: boolean = true`, `overflowLabel: string = "Show remaining members"`, `class: string = ""`
- Slots: None
- Events: `overflow`
### Badge
Theme-aware, responsive badge component.
- Mount: `data-component="Badge"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Badge"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Props: `label: string = "Badge"`, `size: string = "md"`, `color: string = "primary"`, `variant: string = "solid"`, `shape: string = "pill"`, `class: string = ""`, `icon: string = ""`, `iconPosition: string = "start"`, `dot: boolean = false`, `dotOnly: boolean = false`, `dotLabel: string = "Status"`, `animated: boolean = false`, `avatarSrc: string = ""`, `avatarAlt: string = ""`, `dismissible: boolean = false`, `dismissLabel: string = "Remove badge"`, `truncate: boolean = false`, `maxWidth: string = "12rem"`, `anchorLabel: string = ""`, `anchorIcon: string = ""`, `placement: string = "inline"`, `anchorLabelText: string = "Badge anchor"`
- Slots: None
- Events: `dismiss`
### Blockquote
Theme-aware, responsive blockquote component.
- Mount: `data-component="Blockquote"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Blockquote"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Props: `quote: string = "I just wanted to say that I'm very happy with my purchase so far. The documentation is outstanding - clear and detailed."`, `citation: string = ""`, `citationTitle: string = ""`, `citationUrl: string = ""`, `avatarSrc: string = ""`, `avatarAlt: string = ""`, `size: string = "md"`, `color: string = "primary"`, `align: string = "left"`, `variant: string = "default"`, `quoteMark: boolean = true`, `italic: boolean = true`, `class: string = ""`
- Slots: `default`
- Events: None
@@ -148,79 +148,79 @@ Theme-aware, responsive button component.
- Mount: `data-component="Button"`
- Props: `label: string = "Button"`, `loadingLabel: string = "Loading…"`, `description: string = ""`, `as: string = ""`, `href: string = ""`, `target: string = ""`, `rel: string = ""`, `type: string = "button"`, `variant: string = "default"`, `color: string = "primary"`, `size: string = "default"`, `disabled: boolean = false`, `loading: boolean = false`, `pill: boolean = false`, `fullWidth: boolean = false`, `icon: string = ""`, `iconPosition: string = "start"`, `ariaLabel: string = ""`, `ariaPressed: string = ""`, `ariaExpanded: string = ""`, `ariaControls: string = ""`, `title: string = ""`, `autofocus: boolean = false`, `controlClass: string = ""`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `click`, `focus`, `blur`
### ButtonGroup
Theme-aware, responsive button group component.
- Mount: `data-component="ButtonGroup"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Button Group"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Props: `items: string = []`, `value: string = ""`, `size: string = "md"`, `color: string = "primary"`, `variant: string = "default"`, `orientation: string = "horizontal"`, `responsive: boolean = false`, `attached: boolean = true`, `selectable: boolean = false`, `toolbar: boolean = false`, `disabled: boolean = false`, `ariaLabel: string = "Button group"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `click`, `select`, `change`
### Card
Theme-aware, responsive card component.
- Mount: `data-component="Card"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Card"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Props: `title: string = "Card title"`, `subtitle: string = ""`, `description: string = ""`, `header: string = ""`, `footer: string = ""`, `imageSrc: string = ""`, `imageAlt: string = ""`, `imagePosition: string = "top"`, `actionLabel: string = ""`, `actionHref: string = ""`, `headerActions: string = []`, `navigation: string = []`, `activeNav: string = ""`, `mobileNavigation: boolean = false`, `alertTitle: string = ""`, `alertDescription: string = ""`, `empty: boolean = false`, `emptyTitle: string = "No data to show"`, `emptyIcon: string = "icon-[lucide--inbox]"`, `items: string = []`, `size: string = "md"`, `color: string = "primary"`, `variant: string = "default"`, `layout: string = "vertical"`, `align: string = "left"`, `hover: string = "none"`, `scrollable: boolean = false`, `maxHeight: string = "18rem"`, `dismissible: boolean = false`, `ariaLabel: string = ""`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `click`, `action`, `navigate`, `dismiss`, `load`, `error`
### Carousel
Theme-aware, responsive carousel component.
- Mount: `data-component="Carousel"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Carousel"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = ""`, `description: string = ""`, `items: string = []`, `activeIndex: number = 0`, `slidesPerView: number = 1`, `gap: string = "0.75rem"`, `showPagination: boolean = false`, `isAutoPlay: boolean = false`, `autoplayInterval: number = 4000`, `isInfiniteLoop: boolean = false`, `isRTL: boolean = false`, `isCentered: boolean = false`, `isDraggable: boolean = false`, `isAutoHeight: boolean = false`, `isSnap: boolean = false`, `showCounter: boolean = false`, `thumbnails: string = "none"`, `ariaLabel: string = "Content carousel"`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `initialize`, `change`, `previous`, `next`, `play`, `pause`, `reachStart`, `reachEnd`, `dragStart`, `dragEnd`
### ChatBubble
Theme-aware, responsive chat bubble component.
- Mount: `data-component="ChatBubble"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Chat Bubble"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = ""`, `description: string = ""`, `items: string = []`, `oneSided: boolean = false`, `showAvatars: boolean = false`, `showMetadata: boolean = false`, `ariaLabel: string = "Conversation"`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `action`, `messageClick`, `avatarClick`, `linkClick`
### Collapse
Theme-aware, responsive collapse component.
- Mount: `data-component="Collapse"`
- Props: `size: string = "default"`, `color: string = "primary"`, `items: string = []`, `multiple: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `items: string = []`, `multiple: boolean = false`, `mode: string = "panel"`, `initialOpenIndexes: string = []`, `ariaLabel: string = "Collapsible content"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `toggle`, `open`, `close`
### DatePicker
Theme-aware, responsive date picker component.
- Mount: `data-component="DatePicker"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Date Picker"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "date"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Date Picker"`, `id: string = ""`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "date"`, `locale: string = "en-US"`, `firstDayOfWeek: number = 0`, `months: string = [{ label: "Jan", value: "01" }, { label: "Feb", value: "02" }, { label: "Mar", value: "03" }, { label: "Apr", value: "04" }, { label: "May", value: "05" }, { label: "Jun", value: "06" }, { label: "Jul", value: "07" }, { label: "Aug", value: "08" }, { label: "Sep", value: "09" }, { label: "Oct", value: "10" }, { label: "Nov", value: "11" }, { label: "Dec", value: "12" }]`, `days: string = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]`, `years: string = [2024, 2025, 2026, 2027, 2028, 2029, 2030]`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `variant: string = "normal"`, `inline: boolean = false`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Slots: None
- Events: None
- Events: `input`, `change`, `open`, `close`, `focus`, `blur`, `invalid`
### DeviceFrame
Theme-aware, responsive device frame component.
- Mount: `data-component="DeviceFrame"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Device Frame"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Device Frame"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `device: string = "phone"`, `orientation: string = "portrait"`, `src: string = ""`, `srcdoc: string = ""`, `frameTitle: string = "Device preview"`, `showToolbar: boolean = true`, `allow: string = ""`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `change`, `rotate`
### FileUploadProgress
Theme-aware, responsive file upload progress component.
- Mount: `data-component="FileUploadProgress"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Progress"`, `value: number = 50`, `max: number = 100`, `showValue: boolean = true`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Progress"`, `value: number = 50`, `max: number = 100`, `showValue: boolean = true`, `fileName: string = ""`, `fileSize: string = ""`, `uploadedSize: string = ""`, `status: string = "uploading"`, `cancelLabel: string = "Cancel upload"`, `retryLabel: string = "Retry upload"`, `class: string = ""`
- Slots: None
- Events: None
- Events: `cancel`, `retry`, `complete`
### LegendIndicator
@@ -229,7 +229,7 @@ Theme-aware, responsive legend indicator component.
- Mount: `data-component="LegendIndicator"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Legend Indicator"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `toggle`, `select`
### List
@@ -238,7 +238,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: None
- Events: `select`, `click`
### ListGroup
@@ -247,7 +247,7 @@ Theme-aware, responsive list group component.
- Mount: `data-component="ListGroup"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "List Group"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `select`, `change`
### Marquee
@@ -256,7 +256,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: None
- Events: `pause`, `resume`
### Progress
@@ -274,7 +274,7 @@ Theme-aware, responsive rating component.
- Mount: `data-component="Rating"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Rating"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `input`, `change`
### Skeleton
@@ -310,7 +310,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: None
- Events: `select`
### Toast
@@ -319,7 +319,7 @@ Theme-aware, responsive toast component.
- Mount: `data-component="Toast"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Toast"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `dismiss`, `action`
### TreeView
@@ -328,7 +328,7 @@ Theme-aware, responsive tree view component.
- Mount: `data-component="TreeView"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Tree View"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `select`, `toggle`, `expand`, `collapse`
## Forms
@@ -337,99 +337,99 @@ Theme-aware, responsive tree view component.
Theme-aware, responsive checkbox component.
- Mount: `data-component="Checkbox"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Checkbox"`, `name: string = ""`, `value: string = "on"`, `checked: boolean = false`, `disabled: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Checkbox"`, `hiddenLabel: boolean = false`, `placeholder: string = ""`, `variant: string = "normal"`, `icon: string = ""`, `iconPosition: string = "start"`, `value: string = "on"`, `values: string = []`, `options: string = []`, `checked: boolean = false`, `indeterminate: boolean = false`, `orientation: string = "vertical"`, `card: boolean = false`, `rightAligned: boolean = false`, `list: boolean = false`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Slots: None
- Events: None
- Events: `input`, `change`, `focus`, `blur`, `invalid`
### ColorPicker
Theme-aware, responsive color picker component.
- Mount: `data-component="ColorPicker"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Color Picker"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "color"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Color"`, `hiddenLabel: boolean = false`, `placeholder: string = ""`, `value: string = "#2563eb"`, `icon: string = ""`, `iconPosition: string = "start"`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `variant: string = "normal"`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Slots: None
- Events: None
- Events: `input`, `change`, `focus`, `blur`
### FileInput
Theme-aware, responsive file input component.
- Mount: `data-component="FileInput"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "File Input"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "file"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "File"`, `hiddenLabel: boolean = false`, `placeholder: string = "Choose a file"`, `value: string = ""`, `icon: string = "icon-[lucide--upload]"`, `iconPosition: string = "start"`, `accept: string = ""`, `multiple: boolean = false`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `variant: string = "normal"`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Slots: None
- Events: None
- Events: `input`, `change`, `focus`, `blur`, `select`, `clear`, `invalid`
### Input
Theme-aware, responsive input component.
- Mount: `data-component="Input"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Input"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "text"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Input"`, `hiddenLabel: boolean = false`, `placeholder: string = ""`, `value: string = ""`, `type: string = "text"`, `variant: string = "normal"`, `icon: string = ""`, `iconPosition: string = "start"`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `autocomplete: string = ""`, `inputmode: string = ""`, `minlength: string = ""`, `maxlength: string = ""`, `pattern: string = ""`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `class: string = ""`
- Slots: None
- Events: None
- Events: `input`, `change`, `focus`, `blur`, `invalid`, `keydown`, `keyup`
### InputGroup
Theme-aware, responsive input group component.
- Mount: `data-component="InputGroup"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Input Group"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "text"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Input group"`, `hiddenLabel: boolean = false`, `value: string = ""`, `placeholder: string = ""`, `type: string = "text"`, `startText: string = ""`, `endText: string = ""`, `icon: string = ""`, `iconPosition: string = "start"`, `actionLabel: string = ""`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `variant: string = "normal"`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Slots: None
- Events: None
- Events: `input`, `change`, `focus`, `blur`, `submit`, `action`
### Radio
Theme-aware, responsive radio component.
- Mount: `data-component="Radio"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Radio"`, `name: string = ""`, `value: string = "on"`, `checked: boolean = false`, `disabled: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Radio"`, `hiddenLabel: boolean = false`, `placeholder: string = ""`, `variant: string = "normal"`, `icon: string = ""`, `iconPosition: string = "start"`, `value: string = "on"`, `options: string = []`, `checked: boolean = false`, `orientation: string = "vertical"`, `card: boolean = false`, `rightAligned: boolean = false`, `list: boolean = false`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Slots: None
- Events: None
- Events: `input`, `change`, `focus`, `blur`, `invalid`
### RangeSlider
Theme-aware, responsive range slider component.
- Mount: `data-component="RangeSlider"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Range Slider"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "range"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Range"`, `hiddenLabel: boolean = false`, `placeholder: string = ""`, `variant: string = "normal"`, `icon: string = ""`, `iconPosition: string = "start"`, `value: number = 50`, `min: number = 0`, `max: number = 100`, `step: number = 1`, `showValue: boolean = true`, `showBounds: boolean = true`, `showSteps: boolean = false`, `marks: string = []`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Slots: None
- Events: None
- Events: `input`, `change`, `focus`, `blur`
### Select
Theme-aware, responsive select component.
- Mount: `data-component="Select"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Select"`, `name: string = ""`, `value: string = ""`, `options: string = []`, `placeholder: string = "Select an option"`, `multiple: boolean = false`, `disabled: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Select"`, `hiddenLabel: boolean = false`, `value: string = ""`, `values: string = []`, `options: string = []`, `placeholder: string = "Select an option"`, `variant: string = "normal"`, `icon: string = ""`, `iconPosition: string = "start"`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `multiple: boolean = false`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Slots: None
- Events: None
- Events: `input`, `change`, `focus`, `blur`, `open`, `close`, `invalid`
### Switch
Theme-aware, responsive switch component.
- Mount: `data-component="Switch"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Switch"`, `name: string = ""`, `value: string = "on"`, `checked: boolean = false`, `disabled: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Switch"`, `hiddenLabel: boolean = false`, `placeholder: string = ""`, `variant: string = "normal"`, `icon: string = ""`, `iconPosition: string = "start"`, `value: string = "on"`, `checked: boolean = false`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Slots: None
- Events: None
- Events: `input`, `change`, `focus`, `blur`
### Textarea
Theme-aware, responsive textarea component.
- Mount: `data-component="Textarea"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Textarea"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `rows: number = 5`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Textarea"`, `hiddenLabel: boolean = false`, `placeholder: string = ""`, `value: string = ""`, `variant: string = "normal"`, `icon: string = ""`, `iconPosition: string = "start"`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `rows: number = 5`, `resize: string = "vertical"`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `minlength: string = ""`, `maxlength: string = ""`, `class: string = ""`
- Slots: None
- Events: None
- Events: `input`, `change`, `focus`, `blur`, `invalid`
### TimePicker
Theme-aware, responsive time picker component.
- Mount: `data-component="TimePicker"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Time Picker"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "time"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Props: `size: string = "default"`, `color: string = "primary"`, `id: string = ""`, `name: string = ""`, `label: string = "Time"`, `hiddenLabel: boolean = false`, `value: string = ""`, `placeholder: string = ""`, `variant: string = "normal"`, `icon: string = "icon-[lucide--clock-3]"`, `iconPosition: string = "end"`, `helperText: string = ""`, `cornerHint: string = ""`, `error: string = ""`, `inline: boolean = false`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `format: string = "24"`, `minuteStep: number = 5`, `hours: string = ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"]`, `minutes: string = ["00", "05", "10", "15", "20", "25", "30", "35", "40", "45", "50", "55"]`, `readonly: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Slots: None
- Events: None
- Events: `input`, `change`, `focus`, `blur`, `open`, `close`, `invalid`
## Integrations
@@ -440,7 +440,7 @@ Theme-aware, responsive advanced date picker component.
- Mount: `data-component="AdvancedDatePicker"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Advanced Date Picker"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `input`, `change`, `open`, `close`, `clear`
### AdvancedRangeSlider
@@ -449,7 +449,7 @@ Theme-aware, responsive advanced range slider component.
- Mount: `data-component="AdvancedRangeSlider"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Advanced Range Slider"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `input`, `change`, `start`, `end`
### Chart
@@ -458,7 +458,7 @@ Theme-aware, responsive chart component.
- Mount: `data-component="Chart"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Chart"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `select`, `dataPointClick`, `legendToggle`
### Clipboard
@@ -467,7 +467,7 @@ Theme-aware, responsive clipboard component.
- Mount: `data-component="Clipboard"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Clipboard"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `copy`, `success`, `error`
### Confetti
@@ -476,7 +476,7 @@ Theme-aware, responsive confetti component.
- Mount: `data-component="Confetti"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Confetti"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `start`, `complete`
### DataMap
@@ -485,7 +485,7 @@ Theme-aware, responsive data map component.
- Mount: `data-component="DataMap"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Data Map"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `select`, `change`
### DataTable
@@ -494,7 +494,7 @@ Theme-aware, responsive data table component.
- Mount: `data-component="DataTable"`
- Props: `size: string = "default"`, `color: string = "primary"`, `caption: string = "Data Table"`, `columns: string = []`, `rows: string = []`, `striped: boolean = true`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `sort`, `select`, `change`, `rowClick`, `pageChange`
### DragAndDrop
@@ -503,7 +503,7 @@ Theme-aware, responsive drag and drop component.
- Mount: `data-component="DragAndDrop"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Drag And Drop"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `dragStart`, `dragEnd`, `dragEnter`, `dragLeave`, `drop`, `change`
### FileUpload
@@ -512,7 +512,7 @@ Theme-aware, responsive file upload component.
- Mount: `data-component="FileUpload"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "File Upload"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `select`, `upload`, `progress`, `success`, `error`, `cancel`, `remove`
### Map
@@ -521,7 +521,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: None
- Events: `ready`, `move`, `zoom`, `markerClick`
### ToastNotifications
@@ -530,7 +530,7 @@ Theme-aware, responsive toast notifications component.
- Mount: `data-component="ToastNotifications"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Toast Notifications"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `add`, `dismiss`, `clear`, `action`
### WysiwygEditor
@@ -539,7 +539,7 @@ Theme-aware, responsive wysiwyg editor component.
- Mount: `data-component="WysiwygEditor"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Wysiwyg Editor"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `input`, `change`, `focus`, `blur`
## Layout
@@ -568,7 +568,7 @@ Theme-aware, responsive custom scrollbar component.
- Mount: `data-component="CustomScrollbar"`
- Props: `size: string = "default"`, `color: string = "primary"`, `columns: number = 2`, `gap: string = "md"`, `maxWidth: string = "xl"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `scroll`
### Divider
@@ -595,7 +595,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: None
- Events: `load`, `error`
### Kbd
@@ -613,7 +613,7 @@ Theme-aware, responsive layout splitter component.
- Mount: `data-component="LayoutSplitter"`
- Props: `size: string = "default"`, `color: string = "primary"`, `columns: number = 2`, `gap: string = "md"`, `maxWidth: string = "xl"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `resizeStart`, `resize`, `resizeEnd`
### Link
@@ -622,7 +622,7 @@ 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
- Events: `click`, `focus`, `blur`
### Typography
@@ -642,7 +642,7 @@ Theme-aware, responsive breadcrumb component.
- Mount: `data-component="Breadcrumb"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Breadcrumb"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `navigate`, `click`
### MegaMenu
@@ -651,7 +651,7 @@ Theme-aware, responsive mega menu component.
- Mount: `data-component="MegaMenu"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Mega Menu"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `open`, `close`, `select`
### Nav
@@ -660,7 +660,7 @@ Theme-aware, responsive nav component.
- Mount: `data-component="Nav"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Nav"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `select`, `change`
### Navbar
@@ -669,7 +669,7 @@ Theme-aware, responsive navbar component.
- Mount: `data-component="Navbar"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Navbar"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `toggle`, `open`, `close`
### Pagination
@@ -678,7 +678,7 @@ Theme-aware, responsive pagination component.
- Mount: `data-component="Pagination"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Pagination"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `change`, `previous`, `next`
### Scrollspy
@@ -687,7 +687,7 @@ Theme-aware, responsive scrollspy component.
- Mount: `data-component="Scrollspy"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Scrollspy"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `change`
### Sidebar
@@ -696,7 +696,7 @@ Theme-aware, responsive sidebar component.
- Mount: `data-component="Sidebar"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Sidebar"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `toggle`, `open`, `close`
### Stepper
@@ -705,7 +705,7 @@ Theme-aware, responsive stepper component.
- Mount: `data-component="Stepper"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Stepper"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `change`, `previous`, `next`, `complete`
### Tabs
@@ -714,7 +714,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: None
- Events: `change`, `select`
## Overlays
@@ -725,7 +725,7 @@ Theme-aware, responsive context menu component.
- Mount: `data-component="ContextMenu"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Context Menu"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `open`, `close`, `select`
### Drawer
@@ -734,7 +734,7 @@ Theme-aware, responsive drawer component.
- Mount: `data-component="Drawer"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Drawer"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `open`, `close`
### Dropdown
@@ -743,7 +743,7 @@ Theme-aware, responsive dropdown component.
- Mount: `data-component="Dropdown"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Dropdown"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `open`, `close`, `select`, `change`
### Modal
@@ -752,7 +752,7 @@ Theme-aware, responsive modal component.
- Mount: `data-component="Modal"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Modal"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `open`, `close`, `cancel`, `confirm`
### Popover
@@ -761,7 +761,7 @@ Theme-aware, responsive popover component.
- Mount: `data-component="Popover"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Popover"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `open`, `close`
### Tooltip
@@ -770,7 +770,7 @@ Theme-aware, responsive tooltip component.
- Mount: `data-component="Tooltip"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Tooltip"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `open`, `close`
## Tables
@@ -781,4 +781,4 @@ Theme-aware, responsive table component.
- Mount: `data-component="Table"`
- Props: `size: string = "default"`, `color: string = "primary"`, `caption: string = "Table"`, `columns: string = []`, `rows: string = []`, `striped: boolean = true`, `class: string = ""`
- Slots: `default`
- Events: None
- Events: `sort`, `select`, `rowClick`
File diff suppressed because it is too large Load Diff
+193 -5
View File
@@ -2,14 +2,202 @@ component Accordion {
props {
size = "default"
color = "primary"
items = []
multiple = false
variant = "default"
class = ""
id = "accordion"
items = []
defaultOpen = []
multiple = false
alwaysOpen = false
disabled = false
indicator = "plus"
indicatorPosition = "start"
showIndicator = true
bordered = false
separated = false
flush = false
contentItalic = false
@event change = function
@event open = function
@event close = function
}
state openValues = defaultOpen
functions {
function itemValue(item, index) {
return item.value !== undefined && item.value !== ""
? String(item.value)
: String(index)
}
function nestedValue(parent, parentIndex, item, index) {
return itemValue(parent, parentIndex) + "." + itemValue(item, index)
}
function isOpen(value) {
return openValues.includes(value)
}
function allowsMultiple() {
return multiple || alwaysOpen
}
function dispatchAccordionEvent(sourceEvent, eventName, value, item, root, customEvent) {
root = sourceEvent.currentTarget.closest("[data-wrn-accordion]")
if (!root) {
return
}
customEvent = document.createEvent("CustomEvent")
customEvent.initCustomEvent(eventName, true, false, {
component: "Accordion",
value: value,
item: item,
open: isOpen(value),
openValues: openValues
})
root.dispatchEvent(customEvent)
}
function toggleItem(sourceEvent, value, item, wasOpen) {
if (disabled || item.disabled) {
return
}
wasOpen = isOpen(value)
if (wasOpen) {
openValues = openValues.filter((entry) => entry !== value)
} else if (allowsMultiple()) {
openValues = openValues.concat([value])
} else {
openValues = [value]
}
dispatchAccordionEvent(
sourceEvent,
wasOpen ? "close" : "open",
value,
item
)
dispatchAccordionEvent(sourceEvent, "change", value, item)
}
}
view {
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--accordion {class}">
{#each items as item}<details open="{item.open}"><summary>{item.label}</summary><div>{item.content}</div></details>{/each}
<slot />
<div
{...attrs}
id="{id}"
data-wrn-accordion
data-variant="{variant}"
data-indicator="{indicator}"
data-multiple="{allowsMultiple() ? 'true' : 'false'}"
class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--accordion wire-next--accordion-{variant} {bordered ? 'wire-next--accordion-bordered' : ''} {separated ? 'wire-next--accordion-separated' : ''} {flush ? 'wire-next--accordion-flush' : ''} {disabled ? 'wire-next--disabled' : ''} {class}"
>
{#each items as item, index}
<section
class="wire-next__accordion-item"
data-open="{isOpen(itemValue(item, index)) ? 'true' : 'false'}"
data-disabled="{disabled || item.disabled ? 'true' : 'false'}"
>
<h3 class="wire-next__accordion-heading">
<button
type="button"
id="{id}-trigger-{index}"
aria-expanded="{isOpen(itemValue(item, index)) ? 'true' : 'false'}"
aria-controls="{id}-panel-{index}"
disabled="{disabled || item.disabled}"
@click="toggleItem(event, itemValue(item, index), item)"
>
{#if showIndicator && indicatorPosition === "start"}
<span class="wire-next__accordion-indicator" aria-hidden="true">
{#if indicator === "chevron"}
<span class="icon-[lucide--chevron-down]"></span>
{:else}
<span>+</span>
{/if}
</span>
{/if}
<span>{item.label || item.title}</span>
{#if showIndicator && indicatorPosition === "end"}
<span class="wire-next__accordion-indicator" aria-hidden="true">
{#if indicator === "chevron"}
<span class="icon-[lucide--chevron-down]"></span>
{:else}
<span>+</span>
{/if}
</span>
{/if}
</button>
</h3>
<div
id="{id}-panel-{index}"
class="wire-next__accordion-panel"
role="region"
aria-labelledby="{id}-trigger-{index}"
aria-hidden="{isOpen(itemValue(item, index)) ? 'false' : 'true'}"
>
<div>
<div class="wire-next__accordion-content {contentItalic ? 'wire-next__accordion-content-italic' : ''}">
{#if item.content}<p>{item.content}</p>{/if}
{#if item.children && item.children.length > 0}
<div class="wire-next__accordion-nested">
{#each item.children as child, childIndex}
<section
class="wire-next__accordion-item"
data-open="{isOpen(nestedValue(item, index, child, childIndex)) ? 'true' : 'false'}"
>
<h4 class="wire-next__accordion-heading">
<button
type="button"
id="{id}-trigger-{index}-{childIndex}"
aria-expanded="{isOpen(nestedValue(item, index, child, childIndex)) ? 'true' : 'false'}"
aria-controls="{id}-panel-{index}-{childIndex}"
disabled="{disabled || child.disabled}"
@click="toggleItem(event, nestedValue(item, index, child, childIndex), child)"
>
{#if showIndicator}
<span class="wire-next__accordion-indicator" aria-hidden="true">
{#if indicator === "chevron"}
<span class="icon-[lucide--chevron-down]"></span>
{:else}
<span>+</span>
{/if}
</span>
{/if}
<span>{child.label || child.title}</span>
</button>
</h4>
<div
id="{id}-panel-{index}-{childIndex}"
class="wire-next__accordion-panel"
role="region"
aria-labelledby="{id}-trigger-{index}-{childIndex}"
aria-hidden="{isOpen(nestedValue(item, index, child, childIndex)) ? 'false' : 'true'}"
>
<div>
<div class="wire-next__accordion-content {contentItalic ? 'wire-next__accordion-content-italic' : ''}">
<p>{child.content}</p>
</div>
</div>
</div>
</section>
{/each}
</div>
{/if}
</div>
</div>
</div>
</section>
{/each}
</div>
}
}
@@ -1,5 +1,10 @@
component AdvancedDatePicker {
props {
@event input = function
@event change = function
@event open = function
@event close = function
@event clear = function
size = "default"
color = "primary"
title = "Advanced Date Picker"
@@ -1,5 +1,9 @@
component AdvancedRangeSlider {
props {
@event input = function
@event change = function
@event start = function
@event end = function
size = "default"
color = "primary"
title = "Advanced Range Slider"
+113 -11
View File
@@ -1,19 +1,121 @@
component AvatarGroup {
props {
size = "default"
color = "primary"
title = "Avatar Group"
description = ""
items = []
variant = "default"
size = "md"
color = "primary"
variant = "solid"
shape = "circle"
layout = "stack"
maxVisible = 4
columns = 3
borderColor = ""
showTooltips = true
overflowLabel = "Show remaining members"
class = ""
@event overflow = function
}
state overflowOpen = false
functions {
function visibleMembers() {
return items.slice(0, Number(maxVisible))
}
function hiddenMembers() {
return items.slice(Number(maxVisible))
}
function toggleOverflow(sourceEvent, root, customEvent) {
overflowOpen = !overflowOpen
root = sourceEvent.currentTarget.closest("[data-wrn-avatar-group]")
customEvent = document.createEvent("CustomEvent")
customEvent.initCustomEvent("overflow", true, false, {
component: "AvatarGroup",
open: overflowOpen,
hiddenCount: hiddenMembers().length
})
root.dispatchEvent(customEvent)
}
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--avatar-group 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>
<div
{...attrs}
class="wire-next wire-next--avatar-group {class}"
data-wrn-avatar-group
data-layout="{layout}"
data-shape="{shape}"
data-size="{size}"
style="--wire-avatar-group-columns:{columns}; --wire-avatar-group-ring:{borderColor || 'var(--wire-color-bg)'}"
role="group"
aria-label="Avatar group"
>
<div class="wire-next__avatar-group-members">
{#each visibleMembers() as item}
<span
class="wire-next__avatar-group-member"
data-size="{item.size || size}"
data-shape="{item.shape || shape}"
data-color="{item.color || color}"
data-variant="{item.variant || variant}"
tabindex="{showTooltips && (item.tooltip || item.name) ? '0' : '-1'}"
aria-label="{item.name || item.alt || item.initials || 'Group member'}"
>
<span class="wire-next__avatar-group-avatar">
{#if item.src}
<img src="{item.src}" alt="{item.alt || item.name || ''}" loading="lazy" />
{:else if item.initials}
<span aria-hidden="true">{item.initials}</span>
{:else}
<span class="icon-[lucide--user-round]" aria-hidden="true"></span>
{/if}
</span>
{#if showTooltips && (item.tooltip || item.name)}
<span class="wire-next__avatar-group-tooltip" role="tooltip">
{item.tooltip || item.name}
</span>
{/if}
</span>
{/each}
{#if hiddenMembers().length > 0}
<span class="wire-next__avatar-group-overflow">
<button
type="button"
class="wire-next__avatar-group-overflow-button"
aria-label="{overflowLabel}"
aria-expanded="{overflowOpen ? 'true' : 'false'}"
@click="toggleOverflow(event)"
>
+{hiddenMembers().length}
</button>
<span
class="wire-next__avatar-group-menu"
role="menu"
data-show="overflowOpen"
aria-hidden="{overflowOpen ? 'false' : 'true'}"
>
{#each hiddenMembers() as item}
<span class="wire-next__avatar-group-menu-item" role="menuitem">
<span class="wire-next__avatar-group-menu-avatar">
{#if item.src}
<img src="{item.src}" alt="" loading="lazy" />
{:else}
<span>{item.initials || '?'}</span>
{/if}
</span>
<span>{item.name || item.alt || item.initials || 'Team member'}</span>
</span>
{/each}
</span>
</span>
{/if}
</div>
</div>
}
}
+58 -10
View File
@@ -1,19 +1,67 @@
component Blockquote {
props {
size = "default"
quote = "I just wanted to say that I'm very happy with my purchase so far. The documentation is outstanding - clear and detailed."
citation = ""
citationTitle = ""
citationUrl = ""
avatarSrc = ""
avatarAlt = ""
size = "md"
color = "primary"
title = "Blockquote"
description = ""
items = []
align = "left"
variant = "default"
quoteMark = true
italic = true
class = ""
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--blockquote 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>
<figure
{...attrs}
class="wire-next wire-next--blockquote wire-next--color-{color} wire-next--size-{size} {class}"
data-size="{size}"
data-color="{color}"
data-align="{align}"
data-variant="{variant}"
data-italic="{italic}"
>
<blockquote cite="{citationUrl}">
{#if quoteMark}
<span class="wire-next__blockquote-mark" aria-hidden="true">“</span>
{/if}
<div class="wire-next__blockquote-copy">
{#if quote}
<p>{quote}</p>
{:else}
<slot />
{/if}
</div>
</blockquote>
{#if citation || citationTitle || avatarSrc}
<figcaption class="wire-next__blockquote-citation">
{#if avatarSrc}
<img
class="wire-next__blockquote-avatar"
src="{avatarSrc}"
alt="{avatarAlt}"
loading="lazy"
/>
{/if}
<span class="wire-next__blockquote-attribution">
{#if citation}
{#if citationUrl}
<cite><a href="{citationUrl}">{citation}</a></cite>
{:else}
<cite>{citation}</cite>
{/if}
{/if}
{#if citationTitle}<span>{citationTitle}</span>{/if}
</span>
</figcaption>
{/if}
</figure>
}
}
+2
View File
@@ -1,5 +1,7 @@
component Breadcrumb {
props {
@event navigate = function
@event click = function
size = "default"
color = "primary"
label = "Breadcrumb"
+79 -9
View File
@@ -1,19 +1,89 @@
component ButtonGroup {
props {
size = "default"
color = "primary"
title = "Button Group"
description = ""
@event click = function
@event select = function
@event change = function
items = []
value = ""
size = "md"
color = "primary"
variant = "default"
orientation = "horizontal"
responsive = false
attached = true
selectable = false
toolbar = false
disabled = false
ariaLabel = "Button group"
class = ""
}
state selectedValue = value
functions {
function itemValue(item, index) {
return item.value || item.label || String(index)
}
function selectItem(item, index) {
previousValue = selectedValue
nextValue = itemValue(item, index)
$emit("select", {
value: nextValue,
previousValue: previousValue,
item: item,
index: index
})
if (selectable && previousValue !== nextValue) {
selectedValue = nextValue
$emit("change", {
value: nextValue,
previousValue: previousValue,
item: item,
index: index
})
}
}
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--button-group 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}
<div
{...attrs}
class="wire-next wire-next--button-group {class}"
role="{toolbar ? 'toolbar' : 'group'}"
aria-label="{ariaLabel}"
aria-orientation="{orientation}"
data-size="{size}"
data-color="{color}"
data-variant="{variant}"
data-orientation="{orientation}"
data-responsive="{responsive}"
data-attached="{attached}"
data-selectable="{selectable}"
data-disabled="{disabled}"
>
{#if items}
{#each items as item, index}
<button
type="{item.type || 'button'}"
class="wire-btn wire-btn--variant-{item.variant || variant} wire-btn--color-{item.color || color} wire-btn--size-{item.size || size}"
disabled="{disabled || item.disabled}"
aria-label="{item.ariaLabel || item.label}"
aria-pressed="{selectable ? (selectedValue === (item.value || item.label || String(index)) ? 'true' : 'false') : ''}"
data-value="{item.value || item.label || String(index)}"
data-selected="{selectable && selectedValue === (item.value || item.label || String(index)) ? 'true' : 'false'}"
@click="selectItem(item, index)"
>
{#if item.icon}
<span class="wire-btn__icon {item.icon}" aria-hidden="true"></span>
{/if}
<span class="wire-btn__label">{item.label}</span>
</button>
{/each}
{/if}
<slot />
</section>
</div>
}
}
+448 -6
View File
@@ -1,19 +1,461 @@
// Interactive, hydration-safe content carousel.
component Carousel {
props {
@event initialize = function
@event change = function
@event previous = function
@event next = function
@event play = function
@event pause = function
@event reachStart = function
@event reachEnd = function
@event dragStart = function
@event dragEnd = function
size = "default"
color = "primary"
title = "Carousel"
title = ""
description = ""
items = []
activeIndex = 0
slidesPerView = 1
gap = "0.75rem"
showPagination = false
isAutoPlay = false
autoplayInterval = 4000
isInfiniteLoop = false
isRTL = false
isCentered = false
isDraggable = false
isAutoHeight = false
isSnap = false
showCounter = false
thumbnails = "none"
ariaLabel = "Content carousel"
variant = "default"
class = ""
}
state currentIndex = activeIndex
state playing = false
state dragOrigin = null
state dragOffset = 0
state autoplayTimer = null
state carouselRoot = null
functions {
function slideCount() {
return items.length
}
function maximumIndex(count, visible) {
count = slideCount()
visible = Math.max(1, Number(slidesPerView) || 1)
if (isCentered || isSnap) {
return Math.max(0, count - 1)
}
return Math.max(0, count - visible)
}
function normalizedIndex(index, maximum) {
maximum = maximumIndex()
if (slideCount() === 0) {
return 0
}
if (isInfiniteLoop) {
if (index < 0) {
return maximum
}
if (index > maximum) {
return 0
}
}
return Math.max(0, Math.min(index, maximum))
}
function rememberRoot(sourceEvent, root) {
if (!sourceEvent || !sourceEvent.currentTarget) {
return
}
root = sourceEvent.currentTarget.closest(".wire-next--carousel")
if (root) {
carouselRoot = root
}
}
function syncNavigation(sourceEvent, index, root, viewport, slides, slide, thumbnails, thumbnail, rail) {
rememberRoot(sourceEvent)
root = carouselRoot
if (!root) {
return
}
if (isSnap) {
viewport = root.querySelector(".wire-next__carousel-viewport")
slides = root.querySelectorAll(".wire-next__carousel-slide")
slide = slides[index]
if (viewport && slide) {
viewport.scrollTo({
left: slide.offsetLeft - (viewport.clientWidth - slide.clientWidth) / 2,
behavior: "smooth"
})
}
}
thumbnails = root.querySelectorAll(".wire-next__carousel-thumbnails button")
if (thumbnails[index]) {
thumbnail = thumbnails[index]
rail = thumbnail.parentElement
rail.scrollTo({
left: thumbnail.offsetLeft - (rail.clientWidth - thumbnail.clientWidth) / 2,
top: thumbnail.offsetTop - (rail.clientHeight - thumbnail.clientHeight) / 2,
behavior: "smooth"
})
}
}
function handleSnapScroll(sourceEvent, slides, viewport, viewportCenter, closestIndex, closestDistance, slide, slideCenter, distance, previousIndex) {
if (!isSnap) {
return
}
rememberRoot(sourceEvent)
viewport = sourceEvent.currentTarget
slides = viewport.querySelectorAll(".wire-next__carousel-slide")
viewportCenter = viewport.scrollLeft + viewport.clientWidth / 2
closestIndex = currentIndex
closestDistance = 1000000000
slides.forEach(function (candidate, index) {
slideCenter = candidate.offsetLeft + candidate.clientWidth / 2
distance = Math.abs(slideCenter - viewportCenter)
if (distance < closestDistance) {
closestDistance = distance
closestIndex = index
}
})
closestIndex = normalizedIndex(closestIndex)
if (closestIndex !== currentIndex) {
previousIndex = currentIndex
currentIndex = closestIndex
$emit("change", {
index: currentIndex,
previousIndex: previousIndex,
item: items[currentIndex],
reason: "snap"
})
slides = carouselRoot.querySelectorAll(".wire-next__carousel-thumbnails button")
slide = slides[currentIndex]
if (slide) {
viewport = slide.parentElement
viewport.scrollTo({
left: slide.offsetLeft - (viewport.clientWidth - slide.clientWidth) / 2,
top: slide.offsetTop - (viewport.clientHeight - slide.clientHeight) / 2,
behavior: "smooth"
})
}
}
}
function selectSlide(index, reason, sourceEvent, previousIndex) {
if (slideCount() === 0) {
return
}
previousIndex = currentIndex
currentIndex = normalizedIndex(Number(index))
syncNavigation(sourceEvent, currentIndex)
if (previousIndex === currentIndex && reason !== "initialize") {
return
}
$emit("change", {
index: currentIndex,
previousIndex: previousIndex,
item: items[currentIndex],
reason: reason || "select"
})
if (currentIndex === 0) {
$emit("reachStart", { index: currentIndex })
}
if (currentIndex === maximumIndex()) {
$emit("reachEnd", { index: currentIndex })
}
}
function previousSlide(sourceEvent, previousIndex) {
previousIndex = currentIndex
selectSlide(currentIndex - 1, "previous", sourceEvent)
$emit("previous", {
index: currentIndex,
previousIndex: previousIndex,
item: items[currentIndex]
})
}
function nextSlide(sourceEvent, previousIndex) {
previousIndex = currentIndex
selectSlide(currentIndex + 1, "next", sourceEvent)
$emit("next", {
index: currentIndex,
previousIndex: previousIndex,
item: items[currentIndex]
})
}
function handleKeydown(sourceEvent) {
if (sourceEvent.key === "ArrowLeft") {
sourceEvent.preventDefault()
if (isRTL) {
nextSlide(sourceEvent)
} else {
previousSlide(sourceEvent)
}
}
if (sourceEvent.key === "ArrowRight") {
sourceEvent.preventDefault()
if (isRTL) {
previousSlide(sourceEvent)
} else {
nextSlide(sourceEvent)
}
}
if (sourceEvent.key === "Home") {
sourceEvent.preventDefault()
selectSlide(0, "keyboard", sourceEvent)
}
if (sourceEvent.key === "End") {
sourceEvent.preventDefault()
selectSlide(maximumIndex(), "keyboard", sourceEvent)
}
}
function beginDrag(sourceEvent) {
if (!isDraggable || isSnap) {
return
}
sourceEvent.preventDefault()
dragOrigin = sourceEvent.clientX
dragOffset = 0
sourceEvent.currentTarget.setPointerCapture(sourceEvent.pointerId)
$emit("dragStart", { index: currentIndex, x: dragOrigin })
}
function moveDrag(sourceEvent) {
if (!isDraggable || isSnap || dragOrigin === null) {
return
}
sourceEvent.preventDefault()
dragOffset = sourceEvent.clientX - dragOrigin
}
function cancelDrag() {
dragOrigin = null
dragOffset = 0
}
function endDrag(sourceEvent, distance) {
if (!isDraggable || isSnap || dragOrigin === null) {
return
}
sourceEvent.preventDefault()
distance = dragOffset || sourceEvent.clientX - dragOrigin
dragOrigin = null
dragOffset = 0
if (Math.abs(distance) > 20) {
if ((distance < 0 && !isRTL) || (distance > 0 && isRTL)) {
nextSlide(sourceEvent)
} else {
previousSlide(sourceEvent)
}
}
$emit("dragEnd", {
index: currentIndex,
distance: distance
})
}
function advanceAutoplay() {
if (currentIndex >= maximumIndex()) {
selectSlide(0, "autoplay")
} else {
selectSlide(currentIndex + 1, "autoplay")
}
}
function startAutoplay() {
if (!isAutoPlay || playing || slideCount() < 2) {
return
}
playing = true
autoplayTimer = setInterval(advanceAutoplay, Math.max(1000, Number(autoplayInterval)))
$emit("play", { index: currentIndex, interval: autoplayInterval })
}
function pauseAutoplay() {
if (autoplayTimer) {
clearInterval(autoplayTimer)
}
autoplayTimer = null
if (playing) {
$emit("pause", { index: currentIndex })
}
playing = false
}
}
lifecycle {
mount {
$emit("initialize", { index: currentIndex, count: slideCount() })
startAutoplay()
}
unmount {
if (autoplayTimer) {
clearInterval(autoplayTimer)
}
}
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--carousel 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
{...attrs}
class="wire-next wire-next--carousel wire-next--color-{color} wire-next--size-{size} wire-next--variant-{variant} {class}"
data-rtl="{isRTL}"
data-centered="{isCentered}"
data-draggable="{isDraggable && !isSnap}"
data-dragging="{dragOrigin !== null}"
data-auto-height="{isAutoHeight}"
data-snap="{isSnap}"
data-thumbnails="{thumbnails}"
dir="{isRTL ? 'rtl' : 'ltr'}"
role="region"
aria-roledescription="carousel"
aria-label="{ariaLabel}"
@keydown="handleKeydown(event)"
@mouseenter="rememberRoot(event); pauseAutoplay()"
@mouseleave="startAutoplay()"
@focusin="rememberRoot(event); pauseAutoplay()"
@focusout="startAutoplay()"
>
{#if title || description}
<header class="wire-next__carousel-header">
{#if title}<h3>{title}</h3>{/if}
{#if description}<p>{description}</p>{/if}
</header>
{/if}
<div class="wire-next__carousel-layout">
{#if thumbnails === "vertical"}
<div class="wire-next__carousel-thumbnails" aria-label="Choose a slide">
{#each items as item, index}
<button
type="button"
data-active="{index === currentIndex}"
aria-label="Show slide {index + 1}: {item.label || item.title}"
aria-current="{index === currentIndex ? 'true' : 'false'}"
@click="selectSlide(index, 'thumbnail', event)"
>
{#if item.thumbnail}<img src="{item.thumbnail}" alt="" />{/if}
<span>{item.label || item.title || "Slide " + (index + 1)}</span>
</button>
{/each}
</div>
{/if}
<div class="wire-next__carousel-main">
<div class="wire-next__carousel-stage">
<div
class="wire-next__carousel-viewport"
tabindex="0"
@scroll="handleSnapScroll(event)"
@pointerdown="beginDrag(event)"
@pointermove="moveDrag(event)"
@pointerup="endDrag(event)"
@pointercancel="cancelDrag()"
@lostpointercapture="cancelDrag()"
>
<div
class="wire-next__carousel-track"
style="--wire-carousel-index: {currentIndex}; --wire-carousel-per-view: {slidesPerView}; --wire-carousel-gap: {gap}; --wire-carousel-drag-offset: {dragOffset}px"
>
{#each items as item, index}
<article
class="wire-next__carousel-slide"
data-active="{index === currentIndex}"
role="group"
aria-roledescription="slide"
aria-label="{index + 1} of {items.length}"
aria-hidden="{index === currentIndex ? 'false' : 'true'}"
>
{#if item.imageSrc}
<img src="{item.imageSrc}" alt="{item.imageAlt || item.title || ''}" />
{/if}
<div class="wire-next__carousel-slide-content">
{#if item.eyebrow}<span>{item.eyebrow}</span>{/if}
{#if item.title || item.label}<h4>{item.title || item.label}</h4>{/if}
{#if item.description}<p>{item.description}</p>{/if}
{#if item.actionLabel}
<a href="{item.actionHref || '#'}">{item.actionLabel}</a>
{/if}
</div>
</article>
{/each}
<slot />
</div>
</div>
<button
class="wire-next__carousel-control wire-next__carousel-control--previous"
type="button"
aria-label="Previous slide"
disabled="{!isInfiniteLoop && currentIndex === 0}"
@click="previousSlide(event)"
>
<span class="icon-[lucide--chevron-left]" aria-hidden="true"></span>
</button>
<button
class="wire-next__carousel-control wire-next__carousel-control--next"
type="button"
aria-label="Next slide"
disabled="{!isInfiniteLoop && currentIndex === maximumIndex()}"
@click="nextSlide(event)"
>
<span class="icon-[lucide--chevron-right]" aria-hidden="true"></span>
</button>
{#if showCounter}
<output class="wire-next__carousel-counter" aria-live="polite">
{currentIndex + 1} / {items.length}
</output>
{/if}
</div>
{#if showPagination}
<div class="wire-next__carousel-pagination" aria-label="Choose a slide">
{#each items as item, index}
<button
type="button"
data-active="{index === currentIndex}"
aria-label="Show slide {index + 1}"
aria-current="{index === currentIndex ? 'true' : 'false'}"
@click="selectSlide(index, 'pagination', event)"
></button>
{/each}
</div>
{/if}
{#if thumbnails === "horizontal"}
<div class="wire-next__carousel-thumbnails" aria-label="Choose a slide">
{#each items as item, index}
<button
type="button"
data-active="{index === currentIndex}"
aria-label="Show slide {index + 1}: {item.label || item.title}"
aria-current="{index === currentIndex ? 'true' : 'false'}"
@click="selectSlide(index, 'thumbnail', event)"
>
{#if item.thumbnail}<img src="{item.thumbnail}" alt="" />{/if}
<span>{item.label || item.title || "Slide " + (index + 1)}</span>
</button>
{/each}
</div>
{/if}
</div>
</div>
</section>
}
}
+3
View File
@@ -1,5 +1,8 @@
component Chart {
props {
@event select = function
@event dataPointClick = function
@event legendToggle = function
size = "default"
color = "primary"
title = "Chart"
+133 -5
View File
@@ -1,18 +1,146 @@
component ChatBubble {
props {
@event action = function
@event messageClick = function
@event avatarClick = function
@event linkClick = function
size = "default"
color = "primary"
title = "Chat Bubble"
title = ""
description = ""
items = []
oneSided = false
showAvatars = false
showMetadata = false
ariaLabel = "Conversation"
variant = "default"
class = ""
}
functions {
function messageDirection(item) {
return item.direction === "outgoing" ? "outgoing" : "incoming"
}
function selectMessage(item, index) {
$emit("messageClick", {
item: item,
index: index,
direction: messageDirection(item)
})
}
function selectAvatar(sourceEvent, item, index) {
sourceEvent.stopPropagation()
$emit("avatarClick", {
item: item,
index: index,
direction: messageDirection(item)
})
}
function selectLink(sourceEvent, link, item, index) {
sourceEvent.stopPropagation()
$emit("linkClick", {
link: link,
item: item,
index: index
})
}
function selectAction(sourceEvent, item, index) {
sourceEvent.stopPropagation()
$emit("action", {
action: item.action || "retry",
item: item,
index: index
})
}
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--chat-bubble 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}
<section
{...attrs}
class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--chat-bubble wire-next--variant-{variant} {class}"
data-one-sided="{oneSided}"
role="log"
aria-label="{ariaLabel}"
aria-live="polite"
>
{#if title || description}
<header class="wire-next__chat-header">
{#if title}<h3>{title}</h3>{/if}
{#if description}<p>{description}</p>{/if}
</header>
{/if}
{#if items.length}
<div class="wire-next__chat-thread">
{#each items as item, index}
<article
class="wire-next__chat-message"
data-direction="{messageDirection(item)}"
aria-label="{messageDirection(item) === 'outgoing' ? 'Sent message' : 'Received message'}"
>
<div class="wire-next__chat-row">
{#if showAvatars && (item.avatarSrc || item.avatarFallback)}
<button
class="wire-next__chat-avatar"
type="button"
aria-label="{item.avatarLabel || item.author || 'Message author'}"
@click="selectAvatar(event, item, index)"
>
{#if item.avatarSrc}
<img src="{item.avatarSrc}" alt="{item.avatarAlt || ''}" />
{:else}
<span>{item.avatarFallback}</span>
{/if}
</button>
{/if}
<div
class="wire-next__chat-content"
role="button"
tabindex="0"
@click="selectMessage(item, index)"
@keydown="if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); selectMessage(item, index) }"
>
{#if item.title}<h4>{item.title}</h4>{/if}
{#if item.text}<p>{item.text}</p>{/if}
{#if item.bullets && item.bullets.length}
<ul>
{#each item.bullets as bullet}<li>{bullet}</li>{/each}
</ul>
{/if}
{#if item.links && item.links.length}
<nav aria-label="Message links">
{#each item.links as link}
<a
href="{link.href || '#'}"
@click="selectLink(event, link, item, index)"
>{link.label}</a>
{/each}
</nav>
{/if}
</div>
</div>
{#if showMetadata && (item.timestamp || item.status || item.actionLabel)}
<footer class="wire-next__chat-meta" data-tone="{item.statusTone || 'muted'}">
{#if item.statusIcon}<span class="{item.statusIcon}" aria-hidden="true"></span>{/if}
{#if item.status}<span>{item.status}</span>{/if}
{#if item.timestamp}<time datetime="{item.datetime || ''}">{item.timestamp}</time>{/if}
{#if item.actionLabel}
<button type="button" @click="selectAction(event, item, index)">
{item.actionLabel}
</button>
{/if}
</footer>
{/if}
</article>
{/each}
</div>
{/if}
<slot />
</section>
}
+3
View File
@@ -1,5 +1,8 @@
component Clipboard {
props {
@event copy = function
@event success = function
@event error = function
size = "default"
color = "primary"
title = "Clipboard"
+83 -3
View File
@@ -1,15 +1,95 @@
component Collapse {
props {
@event toggle = function
@event open = function
@event close = function
size = "default"
color = "primary"
items = []
multiple = false
mode = "panel"
initialOpenIndexes = []
ariaLabel = "Collapsible content"
class = ""
}
state openIndexes = initialOpenIndexes
functions {
function isOpen(index) {
return openIndexes.includes(index)
}
function toggleItem(index, item, opening) {
if (item.disabled) {
return
}
opening = !isOpen(index)
if (opening) {
if (multiple) {
openIndexes = openIndexes.concat(index)
} else {
openIndexes = [index]
}
$emit("open", { index: index, item: item })
} else {
openIndexes = openIndexes.filter((openIndex) => openIndex !== index)
$emit("close", { index: index, item: item })
}
$emit("toggle", {
index: index,
item: item,
open: opening,
openIndexes: openIndexes
})
}
}
view {
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--collapse {class}">
{#each items as item}<details open="{item.open}"><summary>{item.label}</summary><div>{item.content}</div></details>{/each}
<section
{...attrs}
class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--collapse {class}"
data-mode="{mode}"
aria-label="{ariaLabel}"
>
{#each items as item, index}
<article class="wire-next__collapse-item" data-open="{isOpen(index)}">
{#if mode === "inline" && item.preview}
<p class="wire-next__collapse-preview">{item.preview}</p>
{/if}
<button
class="wire-next__collapse-trigger"
type="button"
aria-expanded="{isOpen(index) ? 'true' : 'false'}"
aria-controls="{item.id || 'collapse-panel-' + index}"
disabled="{item.disabled}"
@click="toggleItem(index, item)"
>
<span>{isOpen(index) ? (item.closeLabel || "Read less") : item.label}</span>
<span class="icon-[lucide--chevron-down] wire-next__collapse-chevron" aria-hidden="true"></span>
</button>
<div
id="{item.id || 'collapse-panel-' + index}"
class="wire-next__collapse-panel"
data-open="{isOpen(index)}"
aria-hidden="{isOpen(index) ? 'false' : 'true'}"
inert="{!isOpen(index)}"
>
<div class="wire-next__collapse-content">
{#if item.title}<h4>{item.title}</h4>{/if}
{#if item.content}<p>{item.content}</p>{/if}
{#if item.links && item.links.length}
<nav aria-label="Related links">
{#each item.links as link}<a href="{link.href || '#'}">{link.label}</a>{/each}
</nav>
{/if}
</div>
</div>
</article>
{/each}
<slot />
</div>
</section>
}
}
+25 -7
View File
@@ -1,20 +1,38 @@
component ColorPicker {
props {
@event input = function
@event change = function
@event focus = function
@event blur = function
size = "default"
color = "primary"
label = "Color Picker"
id = ""
name = ""
value = ""
label = "Color"
hiddenLabel = false
placeholder = ""
type = "color"
min = ""
max = ""
step = ""
value = "#2563eb"
icon = ""
iconPosition = "start"
helperText = ""
cornerHint = ""
error = ""
inline = false
variant = "normal"
readonly = false
disabled = false
required = false
class = ""
}
functions {
function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) }
function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() }
}
view {
<label class="wire-next wire-next--field wire-next--color-picker {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>
<div {...attrs} class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--color-picker {class}" data-variant="{variant}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}">
<div class="wire-next__field-heading"><label class="{hiddenLabel ? 'wire-next__sr-only' : ''}" for="{id || name}">{label}</label>{#if cornerHint}<span class="wire-next__field-hint">{cornerHint}</span>{/if}</div>
<div class="wire-next__color-control" data-icon-position="{iconPosition}">{#if icon}<span class="{icon}" aria-hidden="true"></span>{/if}<input id="{id || name}" type="color" name="{name}" value="{value}" disabled="{disabled}" required="{required}" readonly="{readonly}" aria-invalid="{error ? 'true' : 'false'}" @click="preventReadonly(event)" @input="emitField('input', event)" @change="emitField('change', event)" @focus="emitField('focus', event)" @blur="emitField('blur', event)" /><output>{value}</output></div>
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div>
}
}
+2
View File
@@ -1,5 +1,7 @@
component Confetti {
props {
@event start = function
@event complete = function
size = "default"
color = "primary"
title = "Confetti"
+3
View File
@@ -1,5 +1,8 @@
component ContextMenu {
props {
@event open = function
@event close = function
@event select = function
size = "default"
color = "primary"
title = "Context Menu"
+3
View File
@@ -1,5 +1,8 @@
component CopyMarkup {
props {
@event copy = function
@event success = function
@event error = function
size = "default"
color = "primary"
label = "Copy Markup"
@@ -1,5 +1,6 @@
component CustomScrollbar {
props {
@event scroll = function
size = "default"
color = "primary"
columns = 2
+2
View File
@@ -1,5 +1,7 @@
component DataMap {
props {
@event select = function
@event change = function
size = "default"
color = "primary"
title = "Data Map"
+5
View File
@@ -1,5 +1,10 @@
component DataTable {
props {
@event sort = function
@event select = function
@event change = function
@event rowClick = function
@event pageChange = function
size = "default"
color = "primary"
caption = "Data Table"
+40 -1
View File
@@ -1,20 +1,59 @@
component DatePicker {
props {
@event input = function
@event change = function
@event open = function
@event close = function
@event focus = function
@event blur = function
@event invalid = function
size = "default"
color = "primary"
label = "Date Picker"
id = ""
name = ""
value = ""
placeholder = ""
type = "date"
locale = "en-US"
firstDayOfWeek = 0
months = [{ label: "Jan", value: "01" }, { label: "Feb", value: "02" }, { label: "Mar", value: "03" }, { label: "Apr", value: "04" }, { label: "May", value: "05" }, { label: "Jun", value: "06" }, { label: "Jul", value: "07" }, { label: "Aug", value: "08" }, { label: "Sep", value: "09" }, { label: "Oct", value: "10" }, { label: "Nov", value: "11" }, { label: "Dec", value: "12" }]
days = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
years = [2024, 2025, 2026, 2027, 2028, 2029, 2030]
min = ""
max = ""
step = ""
helperText = ""
cornerHint = ""
error = ""
variant = "normal"
inline = false
readonly = false
disabled = false
required = false
class = ""
}
state currentValue = value
state selectedYear = value ? value.split("-")[0] : ""
state selectedMonth = value ? value.split("-")[1] : ""
state selectedDay = value ? value.split("-")[2] : ""
state expanded = false
functions {
function openCalendar(sourceEvent) { expanded = true; $emit("open", { value: currentValue, name: name, sourceEvent: sourceEvent }) }
function updateDate(part, nextValue, sourceEvent, nextDate, detail) { if (part === "year") { selectedYear = String(nextValue) } if (part === "month") { selectedMonth = String(nextValue).padStart(2, "0") } if (part === "day") { selectedDay = String(nextValue).padStart(2, "0") } if (!selectedYear || !selectedMonth || !selectedDay) { return } nextDate = selectedYear + "-" + selectedMonth + "-" + selectedDay; if ((min && nextDate < min) || (max && nextDate > max)) { return } currentValue = nextDate; detail = { value: currentValue, year: selectedYear, month: selectedMonth, day: selectedDay, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) }
function finishDate(sourceEvent) { if (!currentValue) { return } expanded = false; $emit("close", { value: currentValue, name: name, sourceEvent: sourceEvent }) }
function selectDay(sourceEvent, root, input, nextDate, trigger, detail) { root = sourceEvent.currentTarget.closest(".wire-next--date-picker"); input = root.querySelector(".wire-next__picker-value"); nextDate = input.getAttribute("value").slice(0, 5) + root.querySelector("select").getAttribute("value") + "-" + sourceEvent.currentTarget.dataset.value; currentValue = nextDate; input.setAttribute("value", nextDate); trigger = root.querySelector(".wire-next__date-trigger span"); if (trigger) { trigger.replaceChildren(nextDate) } sourceEvent.currentTarget.setAttribute("aria-pressed", "true"); detail = { value: nextDate, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) }
function clearDate(sourceEvent, detail) { if (disabled || readonly) { return } currentValue = ""; detail = { value: currentValue, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) }
function handleFocus(sourceEvent) { $emit("focus", { value: currentValue, name: name, sourceEvent: sourceEvent }) }
function handleBlur(sourceEvent) { $emit("blur", { value: currentValue, name: name, sourceEvent: sourceEvent }) }
function handleInvalid(sourceEvent) { $emit("invalid", { name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) }
}
view {
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--date-picker {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>
<div {...attrs} class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--date-picker {class}" data-variant="{variant}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}" data-expanded="{expanded}">
<div class="wire-next__field-heading"><label for="{id || name}">{label}</label>{#if cornerHint}<span class="wire-next__field-hint">{cornerHint}</span>{/if}</div>
<div class="wire-next__picker-control"><input id="{id || name}" class="wire-next__sr-only wire-next__picker-value" type="text" name="{name}" value="{currentValue}" required="{required}" readonly aria-hidden="true" tabindex="-1" @invalid="handleInvalid(event)" /><button type="button" class="wire-next__date-trigger" disabled="{disabled || readonly}" aria-haspopup="dialog" aria-expanded="{expanded}" @click="openCalendar(event)" @focus="handleFocus(event)" @blur="handleBlur(event)"><span>{currentValue || placeholder || "Select date"}</span><i class="icon-[lucide--calendar-days]" aria-hidden="true"></i></button>{#if currentValue && !readonly && !disabled}<button type="button" class="wire-next__picker-clear" aria-label="Clear date" @click="clearDate(event)">×</button>{/if}</div>
<div class="wire-next__calendar" role="dialog" aria-label="{label}"><div class="wire-next__date-selectors"><label>Month<select value="{selectedMonth}" @change="updateDate('month', event.currentTarget.value, event)">{#each months as month}<option value="{month.value}" selected="{month.value === selectedMonth}">{month.label}</option>{/each}</select></label><label>Year<select value="{selectedYear}" @change="updateDate('year', event.currentTarget.value, event)">{#each years as year}<option value="{year}" selected="{String(year) === selectedYear}">{year}</option>{/each}</select></label></div><div class="wire-next__calendar-grid">{#each days as day}<button type="button" data-value="{String(day).padStart(2, '0')}" aria-pressed="{String(day).padStart(2, '0') === selectedDay}" @click="selectDay(event)">{day}</button>{/each}</div><button type="button" class="wire-next__date-done" disabled="{!currentValue}" @click="finishDate(event)">Done</button></div>
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div>
}
}
+17 -5
View File
@@ -1,19 +1,31 @@
component DeviceFrame {
props {
@event change = function
@event rotate = function
size = "default"
color = "primary"
title = "Device Frame"
description = ""
items = []
variant = "default"
device = "phone"
orientation = "portrait"
src = ""
srcdoc = ""
frameTitle = "Device preview"
showToolbar = true
allow = ""
class = ""
}
state currentOrientation = orientation
functions {
function setDevice(nextDevice, sourceEvent) { $emit("change", { device: nextDevice, orientation: currentOrientation, sourceEvent: sourceEvent }) }
function rotateFrame(sourceEvent) { currentOrientation = currentOrientation === "portrait" ? "landscape" : "portrait"; $emit("rotate", { device: device, orientation: currentOrientation, sourceEvent: sourceEvent }); $emit("change", { device: device, orientation: currentOrientation, sourceEvent: sourceEvent }) }
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--device-frame 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 {...attrs} class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--device-frame wire-next--variant-{variant} {class}" data-device="{device}" data-orientation="{currentOrientation}">
<header><div>{#if title}<strong>{title}</strong>{/if}{#if description}<p>{description}</p>{/if}</div>{#if showToolbar}<div class="wire-next__device-actions" role="toolbar" aria-label="Preview device">{#each items as item}<button type="button" aria-pressed="{item.value === device}" @click="setDevice(item.value, event)">{item.label}</button>{/each}<button type="button" aria-label="Rotate preview" @click="rotateFrame(event)">↻</button></div>{/if}</header>
<div class="wire-next__device-shell">{#if src || srcdoc}<iframe title="{frameTitle}" src="{src}" srcdoc="{srcdoc}" allow="{allow}"></iframe>{:else}<div class="wire-next__device-content"><slot /></div>{/if}</div>
</section>
}
}
+6
View File
@@ -1,5 +1,11 @@
component DragAndDrop {
props {
@event dragStart = function
@event dragEnd = function
@event dragEnter = function
@event dragLeave = function
@event drop = function
@event change = function
size = "default"
color = "primary"
title = "Drag And Drop"
+2
View File
@@ -1,5 +1,7 @@
component Drawer {
props {
@event open = function
@event close = function
size = "default"
color = "primary"
title = "Drawer"
+4
View File
@@ -1,5 +1,9 @@
component Dropdown {
props {
@event open = function
@event close = function
@event select = function
@event change = function
size = "default"
color = "primary"
title = "Dropdown"
+39 -7
View File
@@ -1,20 +1,52 @@
component FileInput {
props {
@event input = function
@event change = function
@event focus = function
@event blur = function
@event select = function
@event clear = function
@event invalid = function
size = "default"
color = "primary"
label = "File Input"
id = ""
name = ""
label = "File"
hiddenLabel = false
placeholder = "Choose a file"
value = ""
placeholder = ""
type = "file"
min = ""
max = ""
step = ""
icon = "icon-[lucide--upload]"
iconPosition = "start"
accept = ""
multiple = false
helperText = ""
cornerHint = ""
error = ""
inline = false
variant = "normal"
readonly = false
disabled = false
required = false
class = ""
}
state selectedName = ""
functions {
function handleChange(sourceEvent) {
sourceEvent.stopPropagation()
selectedName = sourceEvent.currentTarget.files && sourceEvent.currentTarget.files.length ? sourceEvent.currentTarget.files[0].name : ""
$emit("input", { files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent })
$emit("change", { files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent })
if (selectedName) $emit("select", { files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent })
else $emit("clear", { name: name, sourceEvent: sourceEvent })
}
function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { name: name, sourceEvent: sourceEvent }) }
function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() }
}
view {
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--file-input {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>
<div {...attrs} class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--file-input {class}" data-variant="{variant}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}">
<div class="wire-next__field-heading"><label class="{hiddenLabel ? 'wire-next__sr-only' : ''}" for="{id || name}">{label}</label>{#if cornerHint}<span class="wire-next__field-hint">{cornerHint}</span>{/if}</div>
<div class="wire-next__file-control" data-icon-position="{iconPosition}">{#if icon}<span class="{icon}" aria-hidden="true"></span>{/if}<span>{selectedName || value || placeholder}</span><input id="{id || name}" type="file" name="{name}" accept="{accept}" multiple="{multiple}" disabled="{disabled}" required="{required}" aria-readonly="{readonly}" aria-invalid="{error ? 'true' : 'false'}" @click="preventReadonly(event)" @input="handleChange(event)" @change="handleChange(event)" @focus="emitField('focus', event)" @blur="emitField('blur', event)" @invalid="emitField('invalid', event)" /></div>
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div>
}
}
+7
View File
@@ -1,5 +1,12 @@
component FileUpload {
props {
@event select = function
@event upload = function
@event progress = function
@event success = function
@event error = function
@event cancel = function
@event remove = function
size = "default"
color = "primary"
title = "File Upload"
+23 -3
View File
@@ -1,17 +1,37 @@
component FileUploadProgress {
props {
@event cancel = function
@event retry = function
@event complete = function
size = "default"
color = "primary"
label = "Progress"
value = 50
max = 100
showValue = true
fileName = ""
fileSize = ""
uploadedSize = ""
status = "uploading"
cancelLabel = "Cancel upload"
retryLabel = "Retry upload"
class = ""
}
state currentValue = value
state currentStatus = status
functions {
function percent() { if (!Number(max)) { return 0 } return Math.max(0, Math.min(100, Math.round(Number(currentValue) / Number(max) * 100))) }
function detail(sourceEvent) { return { value: currentValue, max: max, percent: percent(), status: currentStatus, fileName: fileName, sourceEvent: sourceEvent } }
function cancelUpload(sourceEvent) { currentStatus = "cancelled"; $emit("cancel", detail(sourceEvent)) }
function retryUpload(sourceEvent) { currentValue = 0; currentStatus = "uploading"; $emit("retry", detail(sourceEvent)) }
function completeUpload(sourceEvent) { currentValue = max; currentStatus = "complete"; $emit("complete", detail(sourceEvent)) }
}
view {
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--file-upload-progress {class}">
<div class="wire-next__row"><span>{label}</span>{#if showValue}<strong>{value}%</strong>{/if}</div>
<progress value="{value}" max="{max}"></progress>
<div {...attrs} class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--file-upload-progress {class}" data-status="{currentStatus}" aria-live="polite">
<div class="wire-next__row"><span>{#if fileName}<strong>{fileName}</strong><small>{#if uploadedSize || fileSize}{uploadedSize}{#if uploadedSize && fileSize} of {/if}{fileSize}{:else}{label}{/if}</small>{:else}<strong>{label}</strong>{/if}</span>{#if showValue}<strong>{percent()}%</strong>{/if}</div>
<progress value="{currentValue}" max="{max}" aria-label="{label}"></progress>
<div class="wire-next__upload-status"><span class="wire-next__upload-status-icon" aria-hidden="true"></span><span>{#if currentStatus === "uploading"}Uploading securely…{:else if currentStatus === "complete"}Upload complete{:else if currentStatus === "error"}Upload failed{:else}Upload cancelled{/if}</span></div>
<div class="wire-next__upload-actions">{#if currentStatus === "uploading"}<button type="button" @click="cancelUpload(event)">{cancelLabel}</button><button type="button" @click="completeUpload(event)">Complete</button>{/if}{#if currentStatus === "error" || currentStatus === "cancelled"}<button type="button" @click="retryUpload(event)">{retryLabel}</button>{/if}</div>
</div>
}
}
+2
View File
@@ -1,5 +1,7 @@
component Image {
props {
@event load = function
@event error = function
size = "default"
color = "primary"
src = ""
+36 -5
View File
@@ -1,20 +1,51 @@
component InputGroup {
props {
@event input = function
@event change = function
@event focus = function
@event blur = function
@event submit = function
@event action = function
size = "default"
color = "primary"
label = "Input Group"
id = ""
name = ""
label = "Input group"
hiddenLabel = false
value = ""
placeholder = ""
type = "text"
min = ""
max = ""
step = ""
startText = ""
endText = ""
icon = ""
iconPosition = "start"
actionLabel = ""
helperText = ""
cornerHint = ""
error = ""
inline = false
variant = "normal"
readonly = false
disabled = false
required = false
class = ""
}
functions {
function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) }
function handleKeydown(sourceEvent) { if (sourceEvent.key === "Enter") { sourceEvent.stopPropagation(); $emit("submit", { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } }
function handleAction(sourceEvent) { $emit("action", { name: name, sourceEvent: sourceEvent }) }
}
view {
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--input-group {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>
<div {...attrs} class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--input-group {class}" data-variant="{variant}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}">
<div class="wire-next__field-heading"><label class="{hiddenLabel ? 'wire-next__sr-only' : ''}" for="{id || name}">{label}</label>{#if cornerHint}<span class="wire-next__field-hint">{cornerHint}</span>{/if}</div>
<div class="wire-next__input-group-control">
{#if startText}<span class="wire-next__input-addon">{startText}</span>{/if}
{#if icon}<span class="{icon} wire-next__field-icon" data-position="{iconPosition}" aria-hidden="true"></span>{/if}
<input id="{id || name}" type="{type}" name="{name}" value="{value}" placeholder="{placeholder}" readonly="{readonly}" disabled="{disabled}" required="{required}" aria-invalid="{error ? 'true' : 'false'}" @input="emitField('input', event)" @change="emitField('change', event)" @focus="emitField('focus', event)" @blur="emitField('blur', event)" @keydown="handleKeydown(event)" />
{#if endText}<span class="wire-next__input-addon">{endText}</span>{/if}
{#if actionLabel}<button type="button" disabled="{disabled}" @click="handleAction(event)">{actionLabel}</button>{/if}
</div>
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div>
}
}
@@ -1,5 +1,8 @@
component LayoutSplitter {
props {
@event resizeStart = function
@event resize = function
@event resizeEnd = function
size = "default"
color = "primary"
columns = 2
@@ -1,5 +1,7 @@
component LegendIndicator {
props {
@event toggle = function
@event select = function
size = "default"
color = "primary"
title = "Legend Indicator"
+3
View File
@@ -1,5 +1,8 @@
component Link {
props {
@event click = function
@event focus = function
@event blur = function
size = "default"
color = "primary"
label = "Link"
+2
View File
@@ -1,5 +1,7 @@
component List {
props {
@event select = function
@event click = function
size = "default"
color = "primary"
title = "List"
+2
View File
@@ -1,5 +1,7 @@
component ListGroup {
props {
@event select = function
@event change = function
size = "default"
color = "primary"
title = "List Group"
+4
View File
@@ -1,5 +1,9 @@
component Map {
props {
@event ready = function
@event move = function
@event zoom = function
@event markerClick = function
size = "default"
color = "primary"
title = "Map"
+2
View File
@@ -1,5 +1,7 @@
component Marquee {
props {
@event pause = function
@event resume = function
size = "default"
color = "primary"
title = "Marquee"
+3
View File
@@ -1,5 +1,8 @@
component MegaMenu {
props {
@event open = function
@event close = function
@event select = function
size = "default"
color = "primary"
label = "Mega Menu"
+4
View File
@@ -1,5 +1,9 @@
component Modal {
props {
@event open = function
@event close = function
@event cancel = function
@event confirm = function
size = "default"
color = "primary"
title = "Modal"
+2
View File
@@ -1,5 +1,7 @@
component Nav {
props {
@event select = function
@event change = function
size = "default"
color = "primary"
label = "Nav"
+3
View File
@@ -1,5 +1,8 @@
component Navbar {
props {
@event toggle = function
@event open = function
@event close = function
size = "default"
color = "primary"
label = "Navbar"
+3
View File
@@ -1,5 +1,8 @@
component Pagination {
props {
@event change = function
@event previous = function
@event next = function
size = "default"
color = "primary"
label = "Pagination"
+2
View File
@@ -1,5 +1,7 @@
component Popover {
props {
@event open = function
@event close = function
size = "default"
color = "primary"
title = "Popover"
+55 -7
View File
@@ -1,20 +1,68 @@
component RangeSlider {
props {
@event input = function
@event change = function
@event focus = function
@event blur = function
size = "default"
color = "primary"
label = "Range Slider"
id = ""
name = ""
value = ""
label = "Range"
hiddenLabel = false
placeholder = ""
type = "range"
min = ""
max = ""
step = ""
variant = "normal"
icon = ""
iconPosition = "start"
value = 50
min = 0
max = 100
step = 1
showValue = true
showBounds = true
showSteps = false
marks = []
helperText = ""
cornerHint = ""
error = ""
inline = false
readonly = false
disabled = false
required = false
class = ""
}
state currentValue = value
functions {
function percent() { if (Number(max) === Number(min)) { return 0 } return (Number(currentValue) - Number(min)) / (Number(max) - Number(min)) * 100 }
function setValue(nextValue, sourceEvent, commit, detail, root, slider, input, output, progressValue) { if (readonly || disabled) { return } currentValue = Number(nextValue); root = sourceEvent.currentTarget.closest(".wire-next--range-slider"); if (root) { slider = root.querySelector("[role=slider]"); input = root.querySelector("input[name='" + name + "']"); output = root.querySelector("output"); progressValue = (currentValue - Number(min)) / (Number(max) - Number(min)) * 100; if (slider) { slider.setAttribute("aria-valuenow", String(currentValue)); slider.style.setProperty("--wire-range-progress", progressValue + "%") } if (input) { input.value = String(currentValue) } if (output) { output.textContent = String(currentValue) } } detail = { value: currentValue, min: min, max: max, step: step, name: name, sourceEvent: sourceEvent }; $emit("input", detail); if (commit) { $emit("change", detail) } }
function valueFromPointer(sourceEvent, rect, ratio) { rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); return Number(min) + ratio * (Number(max) - Number(min)) }
function beginSlide(sourceEvent, rect, ratio, rawValue) { if (readonly || disabled) { return } sourceEvent.currentTarget.setPointerCapture(sourceEvent.pointerId); rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }) }
function moveSlide(sourceEvent, rect, ratio, rawValue) { if (!sourceEvent.currentTarget.hasPointerCapture(sourceEvent.pointerId)) { return } rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }) }
function endSlide(sourceEvent, rect, ratio, rawValue) { rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); if (sourceEvent.currentTarget.hasPointerCapture(sourceEvent.pointerId)) { sourceEvent.currentTarget.releasePointerCapture(sourceEvent.pointerId) } $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) }
function selectMark(sourceEvent, root, slider, input, output, nextValue, progressValue, detail) { if (readonly || disabled) { return } root = sourceEvent.currentTarget.closest(".wire-next--range-slider"); slider = root.querySelector(".wire-next__custom-slider"); input = root.querySelector(".wire-next__range-value"); output = root.querySelector("output"); nextValue = Number(sourceEvent.currentTarget.dataset.value); currentValue = nextValue; progressValue = (nextValue - Number(min)) / (Number(max) - Number(min)) * 100; slider.setAttribute("aria-valuenow", String(nextValue)); slider.style.setProperty("--wire-range-progress", progressValue + "%"); input.setAttribute("value", String(nextValue)); output.replaceChildren(String(nextValue)); detail = { value: nextValue, min: min, max: max, step: step, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) }
function handleKey(sourceEvent) { if (sourceEvent.key === "ArrowRight") { sourceEvent.preventDefault(); currentValue = Math.min(Number(max), Number(currentValue) + Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "ArrowLeft") { sourceEvent.preventDefault(); currentValue = Math.max(Number(min), Number(currentValue) - Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "Home") { sourceEvent.preventDefault(); currentValue = Number(min); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "End") { sourceEvent.preventDefault(); currentValue = Number(max); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) } }
function emitFocus(nameEvent, sourceEvent) { $emit(nameEvent, { value: currentValue, name: name, sourceEvent: sourceEvent }) }
function decreaseValue(sourceEvent) { currentValue = Math.max(Number(min), Number(currentValue) - Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) }
function increaseValue(sourceEvent) { currentValue = Math.min(Number(max), Number(currentValue) + Number(step)); $emit("input", { value: currentValue, name: name, sourceEvent: sourceEvent }); $emit("change", { value: currentValue, name: name, sourceEvent: sourceEvent }) }
}
view {
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--range-slider {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>
<div {...attrs} class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--range-slider {class}" data-variant="{variant}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}">
<div class="wire-next__field-heading"><label class="{hiddenLabel ? 'wire-next__sr-only' : ''}" for="{id || name}">{label}</label>{#if cornerHint}<span class="wire-next__field-hint">{cornerHint}</span>{/if}</div>
<div class="wire-next__range-control" data-variant="{variant}" data-icon-position="{iconPosition}" data-show-steps="{showSteps}">
{#if icon}<span class="{icon}" aria-hidden="true"></span>{/if}
<button type="button" class="wire-next__range-stepper" aria-label="Decrease {label}" disabled="{disabled || readonly}" @click="decreaseValue(event)"></button>
<div class="wire-next__range-track">
<input id="{id || name}" class="wire-next__sr-only wire-next__range-value" type="number" name="{name}" value="{currentValue}" min="{min}" max="{max}" step="{step}" required="{required}" readonly />
<div class="wire-next__custom-slider" role="slider" tabindex="{disabled ? '-1' : '0'}" aria-label="{hiddenLabel ? label : ''}" aria-valuemin="{min}" aria-valuemax="{max}" aria-valuenow="{currentValue}" aria-disabled="{disabled}" aria-readonly="{readonly}" aria-invalid="{error ? 'true' : 'false'}" style="--wire-range-progress: {percent()}%" @pointerdown="beginSlide(event)" @pointermove="moveSlide(event)" @pointerup="endSlide(event)" @pointercancel="endSlide(event)" @keydown="handleKey(event)" @focus="emitFocus('focus', event)" @blur="emitFocus('blur', event)">
<span class="wire-next__slider-fill"></span><span class="wire-next__slider-thumb"></span>
{#if marks.length}<span class="wire-next__slider-marks">{#each marks as mark}<button type="button" data-value="{mark.value}" style="left: {(Number(mark.value) - Number(min)) / (Number(max) - Number(min)) * 100}%" aria-label="{mark.label}" @click="selectMark(event)"></button>{/each}</span>{/if}
</div>
{#if showBounds}<div class="wire-next__range-bounds"><span>{min}</span><span>Step {step}</span><span>{max}</span></div>{/if}
</div>
{#if showValue}<output for="{id || name}">{currentValue}</output>{/if}
<button type="button" class="wire-next__range-stepper" aria-label="Increase {label}" disabled="{disabled || readonly}" @click="increaseValue(event)">+</button>
</div>
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div>
}
}
+2
View File
@@ -1,5 +1,7 @@
component Rating {
props {
@event input = function
@event change = function
size = "default"
color = "primary"
title = "Rating"
+1
View File
@@ -1,5 +1,6 @@
component Scrollspy {
props {
@event change = function
size = "default"
color = "primary"
label = "Scrollspy"
+5
View File
@@ -1,5 +1,10 @@
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"
+3
View File
@@ -1,5 +1,8 @@
component Sidebar {
props {
@event toggle = function
@event open = function
@event close = function
size = "default"
color = "primary"
label = "Sidebar"
+4
View File
@@ -1,5 +1,9 @@
component Stepper {
props {
@event change = function
@event previous = function
@event next = function
@event complete = function
size = "default"
color = "primary"
label = "Stepper"
+2
View File
@@ -1,5 +1,7 @@
component Tabs {
props {
@event change = function
@event select = function
size = "default"
color = "primary"
label = "Tabs"
+46 -3
View File
@@ -1,20 +1,63 @@
component TimePicker {
props {
@event input = function
@event change = function
@event focus = function
@event blur = function
@event open = function
@event close = function
@event invalid = function
size = "default"
color = "primary"
label = "Time Picker"
id = ""
name = ""
label = "Time"
hiddenLabel = false
value = ""
placeholder = ""
type = "time"
variant = "normal"
icon = "icon-[lucide--clock-3]"
iconPosition = "end"
helperText = ""
cornerHint = ""
error = ""
inline = false
min = ""
max = ""
step = ""
format = "24"
minuteStep = 5
hours = ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"]
minutes = ["00", "05", "10", "15", "20", "25", "30", "35", "40", "45", "50", "55"]
readonly = false
disabled = false
required = false
class = ""
}
state currentValue = value
state selectedHour = value ? value.split(":")[0] : "00"
state selectedMinute = value ? value.split(":")[1] : "00"
state expanded = false
functions {
function commit(part, nextValue, sourceEvent, next, detail) { if (part === "hour") { selectedHour = String(nextValue).padStart(2, "0") } if (part === "minute") { selectedMinute = String(nextValue).padStart(2, "0") } next = selectedHour + ":" + selectedMinute; if ((min && next < min) || (max && next > max)) { return } currentValue = next; detail = { value: currentValue, hour: selectedHour, minute: selectedMinute, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) }
function selectTimePart(sourceEvent, root, input, parts, hourValue, minuteValue, next, trigger, detail) { root = sourceEvent.currentTarget.closest(".wire-next--time-picker"); input = root.querySelector(".wire-next__time-value"); parts = String(input.value || value || "00:00").split(":"); hourValue = sourceEvent.currentTarget.dataset.part === "hour" ? sourceEvent.currentTarget.dataset.value : parts[0]; minuteValue = sourceEvent.currentTarget.dataset.part === "minute" ? sourceEvent.currentTarget.dataset.value : parts[1]; next = hourValue + ":" + minuteValue; if ((min && next < min) || (max && next > max)) { return } currentValue = next; input.setAttribute("value", next); trigger = root.querySelector(".wire-next__time-trigger span"); if (trigger) { trigger.replaceChildren(next) } sourceEvent.currentTarget.setAttribute("aria-pressed", "true"); detail = { value: next, hour: hourValue, minute: minuteValue, name: name, sourceEvent: sourceEvent }; $emit("input", detail); $emit("change", detail) }
function openPicker(sourceEvent) { expanded = true; $emit("open", { value: currentValue, name: name, sourceEvent: sourceEvent }) }
function closePicker(sourceEvent) { expanded = false; $emit("close", { value: currentValue, name: name, sourceEvent: sourceEvent }) }
function handleFocus(sourceEvent) { $emit("focus", { value: currentValue, name: name, sourceEvent: sourceEvent }) }
function handleBlur(sourceEvent) { $emit("blur", { value: currentValue, name: name, sourceEvent: sourceEvent }) }
function handleInvalid(sourceEvent) { $emit("invalid", { name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) }
}
view {
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--time-picker {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>
<div {...attrs} class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--time-picker {class}" data-variant="{variant}" data-inline="{inline}" data-floating="{variant === 'floating'}" data-invalid="{error ? 'true' : 'false'}" data-expanded="{expanded}">
<div class="wire-next__field-heading"><label class="{hiddenLabel ? 'wire-next__sr-only' : ''}" for="{id || name}">{label}</label>{#if cornerHint}<span class="wire-next__field-hint">{cornerHint}</span>{/if}</div>
<div class="wire-next__field-control" data-icon-position="{iconPosition}">
{#if icon}<span class="{icon} wire-next__field-icon" aria-hidden="true"></span>{/if}
<input id="{id || name}" class="wire-next__sr-only wire-next__time-value" type="text" name="{name}" value="{currentValue}" required="{required}" readonly aria-hidden="true" tabindex="-1" @invalid="handleInvalid(event)" />
<button type="button" class="wire-next__time-trigger" disabled="{disabled || readonly}" aria-haspopup="dialog" aria-expanded="{expanded}" @click="openPicker(event)" @focus="handleFocus(event)" @blur="handleBlur(event)"><span>{currentValue || placeholder || "Select time"}</span><i class="{icon}" aria-hidden="true"></i></button>
</div>
<div class="wire-next__time-panel" role="dialog" aria-label="{label}"><div><strong>Hour</strong><div class="wire-next__time-options">{#each hours as hour}<button type="button" data-part="hour" data-value="{hour}" aria-pressed="{String(hour) === selectedHour}" @click="selectTimePart(event)">{hour}</button>{/each}</div></div><div><strong>Minute</strong><div class="wire-next__time-options">{#each minutes as minute}<button type="button" data-part="minute" data-value="{minute}" aria-pressed="{String(minute) === selectedMinute}" @click="selectTimePart(event)">{minute}</button>{/each}</div></div><button type="button" class="wire-next__time-done" @click="closePicker(event)">Done</button></div>
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}
<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div>
}
}
+1
View File
@@ -1,5 +1,6 @@
component Timeline {
props {
@event select = function
size = "default"
color = "primary"
title = "Timeline"
+2
View File
@@ -1,5 +1,7 @@
component Toast {
props {
@event dismiss = function
@event action = function
size = "default"
color = "primary"
title = "Toast"
@@ -1,5 +1,9 @@
component ToastNotifications {
props {
@event add = function
@event dismiss = function
@event clear = function
@event action = function
size = "default"
color = "primary"
title = "Toast Notifications"
+228 -11
View File
@@ -2,19 +2,236 @@ component ToggleCount {
props {
size = "default"
color = "primary"
label = "Toggle Count"
name = ""
value = ""
placeholder = ""
type = "text"
min = ""
max = ""
step = ""
disabled = false
required = false
variant = "segmented"
class = ""
name = "billing-cycle"
value = "monthly"
firstValue = "monthly"
firstLabel = "Monthly"
secondValue = "annual"
secondLabel = "Annual"
ariaLabel = "Billing frequency"
items = []
currency = "$"
suffix = ""
firstValueKey = "monthly"
secondValueKey = "annual"
emptyValue = "—"
align = "end"
fullWidth = true
disabled = false
animate = true
animationDuration = 450
animationSteps = 18
@event change = function
@event toggle = function
}
state selectedValue = value
functions {
function isFirstSelected() {
return selectedValue === firstValue
}
function isSecondSelected() {
return selectedValue === secondValue
}
function displayValue(item) {
if (isSecondSelected()) {
return item[secondValueKey] !== undefined
? item[secondValueKey]
: emptyValue
}
return item[firstValueKey] !== undefined
? item[firstValueKey]
: emptyValue
}
function dispatchToggleEvent(sourceEvent, previousValue, root, customEvent) {
root = sourceEvent.currentTarget.closest("[data-wrn-toggle-count]")
if (!root) {
return
}
customEvent = document.createEvent("CustomEvent")
customEvent.initCustomEvent("change", true, false, {
component: "ToggleCount",
name: name,
value: selectedValue,
previousValue: previousValue,
firstValue: firstValue,
secondValue: secondValue
})
root.dispatchEvent(customEvent)
customEvent = document.createEvent("CustomEvent")
customEvent.initCustomEvent("toggle", true, false, {
component: "ToggleCount",
name: name,
value: selectedValue,
previousValue: previousValue,
firstValue: firstValue,
secondValue: secondValue
})
root.dispatchEvent(customEvent)
}
function selectValue(sourceEvent, nextValue, previousValue) {
if (disabled || selectedValue === nextValue) {
return
}
previousValue = selectedValue
selectedValue = nextValue
if (
animate &&
!window.matchMedia("(prefers-reduced-motion: reduce)").matches
) {
animateDisplayedValues(sourceEvent, previousValue)
}
dispatchToggleEvent(sourceEvent, previousValue)
}
function animateDisplayedValues(sourceEvent, previousValue, root, nodes) {
root = sourceEvent.currentTarget.closest("[data-wrn-toggle-count]")
if (!root) {
return
}
nodes = root.querySelectorAll("[data-toggle-count-value]")
animateValueAt(nodes, 0, previousValue)
}
function animateValueAt(nodes, index, previousValue, node, fromValue, toValue) {
if (index >= nodes.length) {
return
}
node = nodes[index]
fromValue = Number(
previousValue === secondValue
? node.getAttribute("data-second-value")
: node.getAttribute("data-first-value")
)
toValue = Number(
selectedValue === secondValue
? node.getAttribute("data-second-value")
: node.getAttribute("data-first-value")
)
if (!Number.isNaN(fromValue) && !Number.isNaN(toValue)) {
animateValueFrame(node, fromValue, toValue, 0)
}
animateValueAt(nodes, index + 1, previousValue)
}
function animateValueFrame(node, fromValue, toValue, frame, totalFrames, nextValue) {
totalFrames = Math.max(1, Number(animationSteps) || 1)
if (frame >= totalFrames) {
node.replaceChildren(String(toValue))
return
}
nextValue = Math.round(
fromValue +
(toValue - fromValue) * (frame / totalFrames)
)
node.replaceChildren(String(nextValue))
setTimeout(
animateValueFrame,
Math.max(1, Number(animationDuration) / totalFrames),
node,
fromValue,
toValue,
frame + 1
)
}
function toggleValue(sourceEvent) {
selectValue(
sourceEvent,
isFirstSelected() ? secondValue : firstValue
)
}
}
view {
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--toggle-count {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>
<section
{...attrs}
data-wrn-toggle-count
data-variant="{variant}"
data-value="{selectedValue}"
data-disabled="{disabled ? 'true' : 'false'}"
class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--toggle-count wire-next--toggle-count-{variant} {fullWidth ? 'wire-next--toggle-count-full' : ''} {disabled ? 'wire-next--disabled' : ''} {class}"
>
<input type="hidden" name="{name}" value="{selectedValue}" />
<div class="wire-next__toggle-count-control wire-next__toggle-count-control--{align}">
{#if variant === "switch"}
<span data-selected="{isFirstSelected() ? 'true' : 'false'}">{firstLabel}</span>
<button
type="button"
role="switch"
aria-label="{ariaLabel}"
aria-checked="{isSecondSelected() ? 'true' : 'false'}"
disabled="{disabled}"
@click="toggleValue(event)"
class="wire-next__toggle-count-switch"
>
<span aria-hidden="true"></span>
</button>
<span data-selected="{isSecondSelected() ? 'true' : 'false'}">{secondLabel}</span>
{:else}
<div class="wire-next__toggle-count-segmented" role="group" aria-label="{ariaLabel}">
<button
type="button"
aria-pressed="{isFirstSelected() ? 'true' : 'false'}"
disabled="{disabled}"
@click="selectValue(event, firstValue)"
>{firstLabel}</button>
<button
type="button"
aria-pressed="{isSecondSelected() ? 'true' : 'false'}"
disabled="{disabled}"
@click="selectValue(event, secondValue)"
>{secondLabel}</button>
</div>
{/if}
</div>
{#if items.length > 0}
<div class="wire-next__toggle-count-items">
{#each items as item}
<article>
<span>{item.label || item.name}</span>
<strong>
{#if currency}<small>{currency}</small>{/if}
<span
data-toggle-count-value
data-first-value="{item[firstValueKey]}"
data-second-value="{item[secondValueKey]}"
>{displayValue(item)}</span>
{#if suffix}<small>{suffix}</small>{/if}
</strong>
{#if item.description}<small>{item.description}</small>{/if}
</article>
{/each}
</div>
{/if}
</section>
}
}
+4
View File
@@ -1,5 +1,9 @@
component TreeView {
props {
@event select = function
@event toggle = function
@event expand = function
@event collapse = function
size = "default"
color = "primary"
title = "Tree View"
+4
View File
@@ -1,5 +1,9 @@
component WysiwygEditor {
props {
@event input = function
@event change = function
@event focus = function
@event blur = function
size = "default"
color = "primary"
title = "Wysiwyg Editor"
+131 -8
View File
@@ -1,19 +1,142 @@
component Alert {
props {
size = "default"
color = "primary"
color = "info"
variant = "soft"
class = ""
radius = "md"
shadow = "sm"
title = "Alert"
description = ""
items = []
variant = "default"
class = ""
actions = []
showIcon = false
icon = ""
dismissible = false
dismissLabel = "Dismiss alert"
role = "alert"
live = "polite"
linkLabel = ""
linkHref = ""
actionLabel = ""
actionHref = ""
compact = false
@event dismiss = function
@event action = function
}
state visible = true
functions {
function dispatchAlertEvent(sourceEvent, eventName, action, root, customEvent) {
root = sourceEvent.currentTarget.closest("[data-wrn-alert]")
if (!root) {
return
}
customEvent = document.createEvent("CustomEvent")
customEvent.initCustomEvent(eventName, true, false, {
component: "Alert",
title: title,
color: color,
variant: variant,
action: action
})
root.dispatchEvent(customEvent)
}
function dismissAlert(sourceEvent) {
visible = false
dispatchAlertEvent(sourceEvent, "dismiss", null)
}
function selectAction(sourceEvent, action) {
dispatchAlertEvent(sourceEvent, "action", action)
}
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--alert 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
{...attrs}
data-wrn-alert
data-color="{color}"
data-variant="{variant}"
data-radius="{radius}"
data-shadow="{shadow}"
data-show="visible"
aria-hidden="{visible ? 'false' : 'true'}"
role="{role}"
aria-live="{live}"
class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--alert wire-next--alert-{variant} {compact ? 'wire-next--alert-compact' : ''} {class}"
>
{#if showIcon}
<span class="wire-next__alert-icon" aria-hidden="true">
{#if icon}
<span class="{icon}"></span>
{:else if color === "success"}
<span class="icon-[lucide--circle-check]"></span>
{:else if color === "danger"}
<span class="icon-[lucide--circle-x]"></span>
{:else if color === "warning"}
<span class="icon-[lucide--triangle-alert]"></span>
{:else}
<span class="icon-[lucide--info]"></span>
{/if}
</span>
{/if}
<div class="wire-next__alert-body">
{#if title}<strong class="wire-next__alert-title">{title}</strong>{/if}
{#if description}<p>{description}</p>{/if}
{#if items.length > 0}
<ul>
{#each items as item}<li>{item.label || item}</li>{/each}
</ul>
{/if}
{#if actions.length > 0 || actionLabel || linkLabel}
<div class="wire-next__alert-actions">
{#each actions as item}
<a
href="{item.href || '#'}"
data-variant="{item.variant || 'link'}"
@click="selectAction(event, item)"
>{item.label}</a>
{/each}
{#if actionLabel}
<a
href="{actionHref || '#'}"
data-variant="action"
@click="selectAction(event, { label: actionLabel, href: actionHref })"
>{actionLabel}</a>
{/if}
{#if linkLabel}
<a
href="{linkHref || '#'}"
data-variant="link"
@click="selectAction(event, { label: linkLabel, href: linkHref })"
>{linkLabel}</a>
{/if}
</div>
{/if}
</div>
{#if dismissible}
<button
type="button"
class="wire-next__alert-dismiss"
aria-label="{dismissLabel}"
@click="dismissAlert(event)"
>
<span class="icon-[lucide--x]" aria-hidden="true"></span>
</button>
{/if}
</section>
}
}
+78 -10
View File
@@ -1,19 +1,87 @@
component Avatar {
props {
size = "default"
@event load = function
@event error = function
@event click = function
src = ""
alt = ""
initials = ""
size = "md"
color = "primary"
title = "Avatar"
variant = "solid"
shape = "circle"
status = ""
statusLabel = ""
statusPosition = "bottom"
badge = ""
badgeIcon = ""
badgeLabel = ""
tooltip = ""
name = ""
description = ""
items = []
variant = "default"
loading = "lazy"
class = ""
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--avatar 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>
<span
{...attrs}
class="wire-next wire-next--avatar {description ? 'wire-next--avatar-media' : ''} {class}"
data-wrn-avatar
>
<span
class="wire-next__avatar-wrap"
data-shape="{shape}"
data-size="{size}"
data-color="{color}"
data-variant="{variant}"
data-status-position="{statusPosition}"
tabindex="{tooltip ? '0' : '-1'}"
aria-label="{tooltip || name || alt || initials || 'Avatar'}"
>
<span class="wire-next__avatar">
{#if src}
<img src="{src}" alt="{alt || name}" loading="{loading}" />
{:else if initials}
<span class="wire-next__avatar-initials" aria-hidden="true">{initials}</span>
{:else}
<span class="wire-next__avatar-placeholder icon-[lucide--user-round]" aria-hidden="true"></span>
{/if}
</span>
{#if status}
<span
class="wire-next__avatar-status"
data-status="{status}"
title="{statusLabel || status}"
aria-label="{statusLabel || status}"
></span>
{/if}
{#if badgeIcon}
<span class="wire-next__avatar-badge" aria-label="{badgeLabel || 'Linked account'}">
<span class="{badgeIcon}" aria-hidden="true"></span>
</span>
{:else if badge}
<span class="wire-next__avatar-badge wire-next__avatar-badge--text" aria-label="{badgeLabel || badge}">
{badge}
</span>
{/if}
{#if tooltip}
<span class="wire-next__avatar-tooltip" role="tooltip">{tooltip}</span>
{/if}
</span>
{#if description}
<span class="wire-next__avatar-copy">
<strong>{name || alt || initials}</strong>
<span>{description}</span>
</span>
{/if}
</span>
}
}
+94 -11
View File
@@ -1,19 +1,102 @@
component Badge {
props {
size = "default"
label = "Badge"
size = "md"
color = "primary"
title = "Badge"
description = ""
items = []
variant = "default"
variant = "solid"
shape = "pill"
class = ""
icon = ""
iconPosition = "start"
dot = false
dotOnly = false
dotLabel = "Status"
animated = false
avatarSrc = ""
avatarAlt = ""
dismissible = false
dismissLabel = "Remove badge"
truncate = false
maxWidth = "12rem"
anchorLabel = ""
anchorIcon = ""
placement = "inline"
anchorLabelText = "Badge anchor"
@event dismiss = function
}
state visible = true
functions {
function dismissBadge(sourceEvent, root, customEvent) {
visible = false
root = sourceEvent.currentTarget.closest("[data-wrn-badge]")
customEvent = document.createEvent("CustomEvent")
customEvent.initCustomEvent("dismiss", true, false, {
component: "Badge",
label: label
})
root.dispatchEvent(customEvent)
}
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--badge 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>
<span
{...attrs}
class="wire-next wire-next--badge-root {anchorLabel || anchorIcon ? 'wire-next--badge-anchored' : ''} {class}"
data-wrn-badge
data-placement="{placement}"
data-show="visible"
aria-hidden="{visible ? 'false' : 'true'}"
>
{#if anchorLabel || anchorIcon}
<button type="button" class="wire-next__badge-anchor" aria-label="{anchorLabelText}">
{#if anchorIcon}<span class="{anchorIcon}" aria-hidden="true"></span>{/if}
{#if anchorLabel}<span>{anchorLabel}</span>{/if}
</button>
{/if}
<span
class="wire-next__badge"
data-size="{size}"
data-color="{color}"
data-variant="{variant}"
data-shape="{shape}"
data-animated="{animated ? 'true' : 'false'}"
style="--wire-badge-max-width:{maxWidth}"
role="{dotOnly ? 'status' : ''}"
aria-label="{dotOnly ? dotLabel : ''}"
>
{#if animated}
<span class="wire-next__badge-ping" aria-hidden="true"></span>
{/if}
{#if avatarSrc}
<img class="wire-next__badge-avatar" src="{avatarSrc}" alt="{avatarAlt}" loading="lazy" />
{/if}
{#if dot || dotOnly}
<span class="wire-next__badge-dot" aria-hidden="true"></span>
{/if}
{#if icon && iconPosition === "start"}
<span class="wire-next__badge-icon {icon}" aria-hidden="true"></span>
{/if}
{#if !dotOnly}
<span class="wire-next__badge-label {truncate ? 'wire-next__badge-label--truncate' : ''}">
{label}
</span>
{/if}
{#if icon && iconPosition === "end"}
<span class="wire-next__badge-icon {icon}" aria-hidden="true"></span>
{/if}
{#if dismissible}
<button type="button" class="wire-next__badge-dismiss" aria-label="{dismissLabel}" @click="dismissBadge(event)">
<span class="icon-[lucide--x]" aria-hidden="true"></span>
</button>
{/if}
</span>
</span>
}
}
+3
View File
@@ -1,5 +1,8 @@
component Button {
props {
@event click = function
@event focus = function
@event blur = function
label = "Button"
loadingLabel = "Loading…"
description = ""
+248 -8
View File
@@ -1,19 +1,259 @@
component Card {
props {
size = "default"
color = "primary"
title = "Card"
@event click = function
@event action = function
@event navigate = function
@event dismiss = function
@event load = function
@event error = function
title = "Card title"
subtitle = ""
description = ""
header = ""
footer = ""
imageSrc = ""
imageAlt = ""
imagePosition = "top"
actionLabel = ""
actionHref = ""
headerActions = []
navigation = []
activeNav = ""
mobileNavigation = false
alertTitle = ""
alertDescription = ""
empty = false
emptyTitle = "No data to show"
emptyIcon = "icon-[lucide--inbox]"
items = []
size = "md"
color = "primary"
variant = "default"
layout = "vertical"
align = "left"
hover = "none"
scrollable = false
maxHeight = "18rem"
dismissible = false
ariaLabel = ""
class = ""
}
state visible = true
state selectedNav = activeNav
functions {
function chooseNavigation(item, index) {
previousValue = selectedNav
selectedNav = item.value || item.label
$emit("navigate", {
value: selectedNav,
previousValue: previousValue,
item: item,
index: index
})
}
function chooseMobileNavigation(sourceEvent) {
previousValue = selectedNav
selectedNav = sourceEvent.target.value
$emit("navigate", {
value: selectedNav,
previousValue: previousValue
})
}
function chooseAction(action, index) {
$emit("action", {
action: action,
index: index
})
}
function dismissCard(sourceEvent) {
panel = sourceEvent.currentTarget.closest(".wire-next__card-panel")
if (panel) {
panel.setAttribute("hidden", "")
}
visible = false
$emit("dismiss", {
title: title
})
}
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--card 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
{...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}"
>
{#if items.length > 0}
<div class="wire-next__card-group">
{#each items as item}
<article class="wire-next__card-panel">
{#if item.imageSrc}
<div class="wire-next__card-media">
<img src="{item.imageSrc}" alt="{item.imageAlt || ''}" loading="lazy" />
</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>
{#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">
<img
src="{imageSrc}"
alt="{imageAlt}"
loading="lazy"
@load="$emit('load', { src: imageSrc })"
@error="$emit('error', { 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>
{:else}
{#if header || headerActions.length > 0 || dismissible}
<header class="wire-next__card-header">
<span>{header}</span>
{#if headerActions.length > 0 || dismissible}
<span class="wire-next__card-header-actions">
{#each headerActions as action, index}
<button
type="button"
aria-label="{action.ariaLabel || action.label}"
title="{action.label}"
@click="chooseAction(action, index)"
>
{#if action.icon}<span class="{action.icon}" aria-hidden="true"></span>{/if}
{#if !action.icon}<span>{action.label}</span>{/if}
</button>
{/each}
{#if dismissible}
<button type="button" aria-label="Close card" @click="dismissCard(event)">
<span class="icon-[lucide--x]" aria-hidden="true"></span>
</button>
{/if}
</span>
{/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>
{#if mobileNavigation}
<select
class="wire-next__card-navigation-select"
aria-label="{ariaLabel || title}"
value="{selectedNav}"
@change="chooseMobileNavigation(event)"
>
{#each navigation as item}
<option
value="{item.value || item.label}"
selected="{selectedNav === (item.value || item.label)}"
>
{item.label}
</option>
{/each}
</select>
{/if}
</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>
{/if}
<div
class="wire-next__card-body"
data-scrollable="{scrollable}"
style="--wire-card-max-height: {maxHeight}"
>
{#if empty}
<div class="wire-next__card-empty">
<span class="{emptyIcon}" aria-hidden="true"></span>
<strong>{emptyTitle}</strong>
</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}
{/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}
{/if}
</article>
{/if}
</section>
}
}
+49 -2
View File
@@ -1,15 +1,62 @@
component Checkbox {
props {
@event input = function
@event change = function
@event focus = function
@event blur = function
@event invalid = function
size = "default"
color = "primary"
label = "Checkbox"
id = ""
name = ""
label = "Checkbox"
hiddenLabel = false
placeholder = ""
variant = "normal"
icon = ""
iconPosition = "start"
value = "on"
values = []
options = []
checked = false
indeterminate = false
orientation = "vertical"
card = false
rightAligned = false
list = false
helperText = ""
cornerHint = ""
error = ""
inline = false
readonly = false
disabled = false
required = false
class = ""
}
functions {
function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { checked: sourceEvent.currentTarget.checked, value: sourceEvent.currentTarget.value, values: values, name: name, sourceEvent: sourceEvent }) }
function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() }
}
view {
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--choice wire-next--checkbox {class}"><input {...attrs} type="checkbox" name="{name}" value="{value}" checked="{checked}" disabled="{disabled}" /><span>{label}</span></label>
<div {...attrs} class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--choice-field wire-next--checkbox-field {class}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}" data-orientation="{orientation}" data-card="{card}" data-list="{list}" data-right-aligned="{rightAligned}">
<div class="wire-next__field-heading">{#if options.length || cornerHint}<span class="{hiddenLabel ? 'wire-next__sr-only' : ''}">{label}</span>{#if cornerHint}<span class="wire-next__field-hint">{cornerHint}</span>{/if}{/if}</div>
{#if options.length}
<div class="wire-next__checkbox-group" role="group" aria-label="{hiddenLabel ? label : ''}" aria-invalid="{error ? 'true' : 'false'}">
{#each options as option}
<label class="wire-next__choice wire-next--checkbox" for="{id || name}-{option.value}" data-variant="{variant}" data-disabled="{disabled || option.disabled}">
<input id="{id || name}-{option.value}" type="checkbox" name="{name}" value="{option.value}" checked="{values.includes(option.value) || option.checked}" disabled="{disabled || option.disabled}" required="{required}" readonly="{readonly}" @click="preventReadonly(event)" @input="emitField('input', event)" @change="emitField('change', event)" @focus="emitField('focus', event)" @blur="emitField('blur', event)" @invalid="emitField('invalid', event)" />
<span class="wire-next__choice-copy"><strong>{option.label}</strong>{#if option.description}<small>{option.description}</small>{/if}</span>
</label>
{/each}
</div>
{:else}
<label class="wire-next__choice wire-next--checkbox" for="{id || name}" data-variant="{variant}" data-icon-position="{iconPosition}">
<input id="{id || name}" type="checkbox" name="{name}" value="{value}" checked="{checked}" disabled="{disabled}" required="{required}" readonly="{readonly}" aria-checked="{indeterminate ? 'mixed' : (checked ? 'true' : 'false')}" aria-invalid="{error ? 'true' : 'false'}" @click="preventReadonly(event)" @input="emitField('input', event)" @change="emitField('change', event)" @focus="emitField('focus', event)" @blur="emitField('blur', event)" @invalid="emitField('invalid', event)" />
{#if icon}<span class="{icon}" aria-hidden="true"></span>{/if}
<span class="{hiddenLabel || cornerHint ? 'wire-next__sr-only' : ''}">{label}</span>
</label>
{/if}
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div>
}
}
+77 -5
View File
@@ -1,20 +1,92 @@
component Input {
props {
@event input = function
@event change = function
@event focus = function
@event blur = function
@event invalid = function
@event keydown = function
@event keyup = function
size = "default"
color = "primary"
label = "Input"
id = ""
name = ""
value = ""
label = "Input"
hiddenLabel = false
placeholder = ""
value = ""
type = "text"
variant = "normal"
icon = ""
iconPosition = "start"
helperText = ""
cornerHint = ""
error = ""
inline = false
readonly = false
disabled = false
required = false
autocomplete = ""
inputmode = ""
minlength = ""
maxlength = ""
pattern = ""
min = ""
max = ""
step = ""
disabled = false
required = false
class = ""
}
functions {
function detail(sourceEvent) {
return { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }
}
function handleInput(sourceEvent) { sourceEvent.stopPropagation(); $emit("input", detail(sourceEvent)) }
function handleChange(sourceEvent) { sourceEvent.stopPropagation(); $emit("change", detail(sourceEvent)) }
function handleFocus(sourceEvent) { sourceEvent.stopPropagation(); $emit("focus", detail(sourceEvent)) }
function handleBlur(sourceEvent) { sourceEvent.stopPropagation(); $emit("blur", detail(sourceEvent)) }
function handleInvalid(sourceEvent) { sourceEvent.stopPropagation(); $emit("invalid", { value: sourceEvent.currentTarget.value, name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) }
function handleKeydown(sourceEvent) { sourceEvent.stopPropagation(); $emit("keydown", { key: sourceEvent.key, value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) }
function handleKeyup(sourceEvent) { sourceEvent.stopPropagation(); $emit("keyup", { key: sourceEvent.key, value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) }
}
view {
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--input {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>
<div {...attrs} class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--input {class}" data-variant="{variant}" data-inline="{inline}" data-floating="{variant === 'floating'}" data-invalid="{error ? 'true' : 'false'}">
<div class="wire-next__field-heading">
<label class="{hiddenLabel ? 'wire-next__sr-only' : ''}" for="{id || name}">{label}</label>
{#if cornerHint}<span class="wire-next__field-hint">{cornerHint}</span>{/if}
</div>
<div class="wire-next__field-control" data-icon-position="{iconPosition}">
{#if icon}<span class="{icon} wire-next__field-icon" aria-hidden="true"></span>{/if}
<input
id="{id || name}"
type="{type}"
name="{name}"
value="{value}"
placeholder="{variant === 'floating' ? ' ' : placeholder}"
readonly="{readonly}"
disabled="{disabled}"
required="{required}"
autocomplete="{autocomplete}"
inputmode="{inputmode}"
minlength="{minlength}"
maxlength="{maxlength}"
pattern="{pattern}"
min="{min}"
max="{max}"
step="{step}"
aria-invalid="{error ? 'true' : 'false'}"
aria-describedby="{error ? (id || name) + '-error' : (helperText ? (id || name) + '-help' : '')}"
@input="handleInput(event)"
@change="handleChange(event)"
@focus="handleFocus(event)"
@blur="handleBlur(event)"
@invalid="handleInvalid(event)"
@keydown="handleKeydown(event)"
@keyup="handleKeyup(event)"
/>
{#if variant === "floating"}<span class="wire-next__field-floating-label">{label}</span>{/if}
</div>
{#if helperText}<small id="{(id || name) + '-help'}" class="wire-next__field-help">{helperText}</small>{/if}
<small id="{(id || name) + '-error'}" class="wire-next__field-error" data-error="{name}">{error}</small>
</div>
}
}
+43 -2
View File
@@ -1,15 +1,56 @@
component Radio {
props {
@event input = function
@event change = function
@event focus = function
@event blur = function
@event invalid = function
size = "default"
color = "primary"
label = "Radio"
id = ""
name = ""
label = "Radio"
hiddenLabel = false
placeholder = ""
variant = "normal"
icon = ""
iconPosition = "start"
value = "on"
options = []
checked = false
orientation = "vertical"
card = false
rightAligned = false
list = false
helperText = ""
cornerHint = ""
error = ""
inline = false
readonly = false
disabled = false
required = false
class = ""
}
functions {
function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { checked: sourceEvent.currentTarget.checked, value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) }
function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() }
}
view {
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--choice wire-next--radio {class}"><input {...attrs} type="radio" name="{name}" value="{value}" checked="{checked}" disabled="{disabled}" /><span>{label}</span></label>
<div {...attrs} class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--choice-field wire-next--radio-field {class}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}" data-orientation="{orientation}" data-card="{card}" data-list="{list}" data-right-aligned="{rightAligned}">
<div class="wire-next__field-heading">{#if options.length || cornerHint}<span class="{hiddenLabel ? 'wire-next__sr-only' : ''}">{label}</span>{#if cornerHint}<span class="wire-next__field-hint">{cornerHint}</span>{/if}{/if}</div>
{#if options.length}
<div class="wire-next__radio-group" role="radiogroup" aria-label="{hiddenLabel ? label : ''}" aria-invalid="{error ? 'true' : 'false'}">
{#each options as option}
<label class="wire-next__choice wire-next--radio" for="{id || name}-{option.value}" data-variant="{variant}" data-disabled="{disabled || option.disabled}">
<input id="{id || name}-{option.value}" type="radio" name="{name}" value="{option.value}" checked="{option.value === value || option.checked}" disabled="{disabled || option.disabled}" required="{required}" readonly="{readonly}" @click="preventReadonly(event)" @input="emitField('input', event)" @change="emitField('change', event)" @focus="emitField('focus', event)" @blur="emitField('blur', event)" @invalid="emitField('invalid', event)" />
<span class="wire-next__choice-copy"><strong>{option.label}</strong>{#if option.description}<small>{option.description}</small>{/if}</span>
</label>
{/each}
</div>
{:else}
<label class="wire-next__choice wire-next--radio" for="{id || name}" data-variant="{variant}" data-icon-position="{iconPosition}"><input id="{id || name}" type="radio" name="{name}" value="{value}" checked="{checked}" disabled="{disabled}" required="{required}" readonly="{readonly}" aria-invalid="{error ? 'true' : 'false'}" @click="preventReadonly(event)" @input="emitField('input', event)" @change="emitField('change', event)" @focus="emitField('focus', event)" @blur="emitField('blur', event)" @invalid="emitField('invalid', event)" />{#if icon}<span class="{icon}" aria-hidden="true"></span>{/if}<span class="{hiddenLabel || cornerHint ? 'wire-next__sr-only' : ''}">{label}</span></label>
{/if}
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div>
}
}
+46 -2
View File
@@ -1,17 +1,61 @@
component Select {
props {
@event input = function
@event change = function
@event focus = function
@event blur = function
@event open = function
@event close = function
@event invalid = function
size = "default"
color = "primary"
label = "Select"
id = ""
name = ""
label = "Select"
hiddenLabel = false
value = ""
values = []
options = []
placeholder = "Select an option"
variant = "normal"
icon = ""
iconPosition = "start"
helperText = ""
cornerHint = ""
error = ""
inline = false
multiple = false
readonly = false
disabled = false
required = false
class = ""
}
functions {
function selected(option) {
if (multiple) return values.includes(option.value)
return option.value === value
}
function emitField(nameEvent, sourceEvent) {
sourceEvent.stopPropagation()
$emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent })
}
function handleFocus(sourceEvent) { emitField("focus", sourceEvent); $emit("open", { name: name, sourceEvent: sourceEvent }) }
function handleBlur(sourceEvent) { emitField("blur", sourceEvent); $emit("close", { name: name, sourceEvent: sourceEvent }) }
function handleInvalid(sourceEvent) { $emit("invalid", { name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) }
}
view {
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--select {class}"><span>{label}</span><select {...attrs} name="{name}" multiple="{multiple}" disabled="{disabled}"><option value="">{placeholder}</option>{#each options as option}<option value="{option.value}" selected="{option.value === value}">{option.label}</option>{/each}</select></label>
<div {...attrs} class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--select {class}" data-variant="{variant}" data-inline="{inline}" data-floating="{variant === 'floating'}" data-invalid="{error ? 'true' : 'false'}" data-readonly="{readonly}">
<div class="wire-next__field-heading"><label class="{hiddenLabel ? 'wire-next__sr-only' : ''}" for="{id || name}">{label}</label>{#if cornerHint}<span class="wire-next__field-hint">{cornerHint}</span>{/if}</div>
<div class="wire-next__field-control" data-icon-position="{iconPosition}">
{#if icon}<span class="{icon} wire-next__field-icon" aria-hidden="true"></span>{/if}
<select id="{id || name}" name="{name}" multiple="{multiple}" disabled="{disabled || readonly}" required="{required}" aria-readonly="{readonly}" aria-invalid="{error ? 'true' : 'false'}" @input="emitField('input', event)" @change="emitField('change', event)" @focus="handleFocus(event)" @blur="handleBlur(event)" @invalid="handleInvalid(event)">
{#if !multiple}<option value="" selected="{value === ''}" disabled="{required}">{placeholder}</option>{/if}
{#each options as option}<option value="{option.value}" selected="{selected(option)}" disabled="{option.disabled}">{option.label}</option>{/each}
</select>
{#if variant === "floating"}<span class="wire-next__field-floating-label">{label}</span>{/if}
</div>
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}
<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div>
}
}
+26 -2
View File
@@ -1,15 +1,39 @@
component Switch {
props {
@event input = function
@event change = function
@event focus = function
@event blur = function
size = "default"
color = "primary"
label = "Switch"
id = ""
name = ""
label = "Switch"
hiddenLabel = false
placeholder = ""
variant = "normal"
icon = ""
iconPosition = "start"
value = "on"
checked = false
helperText = ""
cornerHint = ""
error = ""
inline = false
readonly = false
disabled = false
required = false
class = ""
}
functions {
function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); $emit(nameEvent, { checked: sourceEvent.currentTarget.checked, value: value, name: name, sourceEvent: sourceEvent }) }
function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() }
}
view {
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--choice wire-next--switch {class}"><input {...attrs} type="checkbox" name="{name}" value="{value}" checked="{checked}" disabled="{disabled}" /><span>{label}</span></label>
<div {...attrs} class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--choice-field {class}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}">
<div class="wire-next__field-heading">{#if cornerHint}<span class="{hiddenLabel ? 'wire-next__sr-only' : ''}">{label}</span><span class="wire-next__field-hint">{cornerHint}</span>{/if}</div>
<label class="wire-next__choice wire-next--switch" for="{id || name}" data-variant="{variant}" data-icon-position="{iconPosition}"><input id="{id || name}" type="checkbox" role="switch" name="{name}" value="{value}" checked="{checked}" disabled="{disabled}" required="{required}" readonly="{readonly}" aria-checked="{checked ? 'true' : 'false'}" aria-invalid="{error ? 'true' : 'false'}" @click="preventReadonly(event)" @input="emitField('input', event)" @change="emitField('change', event)" @focus="emitField('focus', event)" @blur="emitField('blur', event)" />{#if icon}<span class="{icon}" aria-hidden="true"></span>{/if}<span class="{hiddenLabel || cornerHint ? 'wire-next__sr-only' : ''}">{label}</span></label>
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div>
}
}
+3
View File
@@ -1,5 +1,8 @@
component Table {
props {
@event sort = function
@event select = function
@event rowClick = function
size = "default"
color = "primary"
caption = "Table"
+39 -3
View File
@@ -1,17 +1,53 @@
component Textarea {
props {
@event input = function
@event change = function
@event focus = function
@event blur = function
@event invalid = function
size = "default"
color = "primary"
label = "Textarea"
id = ""
name = ""
value = ""
label = "Textarea"
hiddenLabel = false
placeholder = ""
value = ""
variant = "normal"
icon = ""
iconPosition = "start"
helperText = ""
cornerHint = ""
error = ""
inline = false
rows = 5
resize = "vertical"
readonly = false
disabled = false
required = false
minlength = ""
maxlength = ""
class = ""
}
functions {
function emitField(nameEvent, sourceEvent) {
sourceEvent.stopPropagation()
$emit(nameEvent, { value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent })
}
function handleInvalid(sourceEvent) {
$emit("invalid", { value: sourceEvent.currentTarget.value, name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent })
}
}
view {
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--textarea {class}"><span>{label}</span><textarea {...attrs} name="{name}" placeholder="{placeholder}" rows="{rows}" disabled="{disabled}" required="{required}">{value}</textarea></label>
<div {...attrs} class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--textarea {class}" data-variant="{variant}" data-inline="{inline}" data-floating="{variant === 'floating'}" data-invalid="{error ? 'true' : 'false'}">
<div class="wire-next__field-heading"><label class="{hiddenLabel ? 'wire-next__sr-only' : ''}" for="{id || name}">{label}</label>{#if cornerHint}<span class="wire-next__field-hint">{cornerHint}</span>{/if}</div>
<div class="wire-next__field-control" data-icon-position="{iconPosition}">
{#if icon}<span class="{icon} wire-next__field-icon" aria-hidden="true"></span>{/if}
<textarea id="{id || name}" name="{name}" placeholder="{variant === 'floating' ? ' ' : placeholder}" rows="{rows}" style="resize: {resize}" readonly="{readonly}" disabled="{disabled}" required="{required}" minlength="{minlength}" maxlength="{maxlength}" aria-invalid="{error ? 'true' : 'false'}" aria-describedby="{error ? (id || name) + '-error' : (helperText ? (id || name) + '-help' : '')}" @input="emitField('input', event)" @change="emitField('change', event)" @focus="emitField('focus', event)" @blur="emitField('blur', event)" @invalid="handleInvalid(event)">{value}</textarea>
{#if variant === "floating"}<span class="wire-next__field-floating-label">{label}</span>{/if}
</div>
{#if helperText}<small id="{(id || name) + '-help'}" class="wire-next__field-help">{helperText}</small>{/if}
<small id="{(id || name) + '-error'}" class="wire-next__field-error" data-error="{name}">{error}</small>
</div>
}
}
+2
View File
@@ -1,5 +1,7 @@
component Tooltip {
props {
@event open = function
@event close = function
size = "default"
color = "primary"
title = "Tooltip"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/ui",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/ui — part of the WrNexus framework.",
"license": "MIT",
@@ -26,7 +26,7 @@
"./ui.css": "./ui.css"
},
"dependencies": {
"@wrnexus/core": "^0.4.0"
"@wrnexus/core": "^0.5.0"
},
"files": [
"dist",
+3668 -14
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/uploader",
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"description": "@wrnexus/uploader — part of the WrNexus framework.",
"license": "MIT",
@@ -21,7 +21,7 @@
}
},
"dependencies": {
"@wrnexus/core": "^0.4.0"
"@wrnexus/core": "^0.5.0"
},
"files": [
"dist"

Some files were not shown because too many files have changed in this diff Show More