release: WRNexusJS 0.5.0
This commit is contained in:
+99
-99
@@ -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`
|
||||
|
||||
+2053
-314
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
component Breadcrumb {
|
||||
props {
|
||||
@event navigate = function
|
||||
@event click = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
label = "Breadcrumb"
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
component Chart {
|
||||
props {
|
||||
@event select = function
|
||||
@event dataPointClick = function
|
||||
@event legendToggle = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
title = "Chart"
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
component Clipboard {
|
||||
props {
|
||||
@event copy = function
|
||||
@event success = function
|
||||
@event error = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
title = "Clipboard"
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
component Confetti {
|
||||
props {
|
||||
@event start = function
|
||||
@event complete = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
title = "Confetti"
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
component ContextMenu {
|
||||
props {
|
||||
@event open = function
|
||||
@event close = function
|
||||
@event select = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
title = "Context Menu"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
component DataMap {
|
||||
props {
|
||||
@event select = function
|
||||
@event change = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
title = "Data Map"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
component Drawer {
|
||||
props {
|
||||
@event open = function
|
||||
@event close = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
title = "Drawer"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
component Image {
|
||||
props {
|
||||
@event load = function
|
||||
@event error = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
src = ""
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
component Link {
|
||||
props {
|
||||
@event click = function
|
||||
@event focus = function
|
||||
@event blur = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
label = "Link"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
component List {
|
||||
props {
|
||||
@event select = function
|
||||
@event click = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
title = "List"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
component ListGroup {
|
||||
props {
|
||||
@event select = function
|
||||
@event change = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
title = "List Group"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
component Marquee {
|
||||
props {
|
||||
@event pause = function
|
||||
@event resume = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
title = "Marquee"
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
component MegaMenu {
|
||||
props {
|
||||
@event open = function
|
||||
@event close = function
|
||||
@event select = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
label = "Mega Menu"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
component Nav {
|
||||
props {
|
||||
@event select = function
|
||||
@event change = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
label = "Nav"
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
component Navbar {
|
||||
props {
|
||||
@event toggle = function
|
||||
@event open = function
|
||||
@event close = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
label = "Navbar"
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
component Pagination {
|
||||
props {
|
||||
@event change = function
|
||||
@event previous = function
|
||||
@event next = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
label = "Pagination"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
component Popover {
|
||||
props {
|
||||
@event open = function
|
||||
@event close = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
title = "Popover"
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
component Rating {
|
||||
props {
|
||||
@event input = function
|
||||
@event change = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
title = "Rating"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
component Scrollspy {
|
||||
props {
|
||||
@event change = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
label = "Scrollspy"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
component Sidebar {
|
||||
props {
|
||||
@event toggle = function
|
||||
@event open = function
|
||||
@event close = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
label = "Sidebar"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
component Tabs {
|
||||
props {
|
||||
@event change = function
|
||||
@event select = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
label = "Tabs"
|
||||
|
||||
@@ -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,5 +1,6 @@
|
||||
component Timeline {
|
||||
props {
|
||||
@event select = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
title = "Timeline"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
component Button {
|
||||
props {
|
||||
@event click = function
|
||||
@event focus = function
|
||||
@event blur = function
|
||||
label = "Button"
|
||||
loadingLabel = "Loading…"
|
||||
description = ""
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
component Table {
|
||||
props {
|
||||
@event sort = function
|
||||
@event select = function
|
||||
@event rowClick = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
caption = "Table"
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
component Tooltip {
|
||||
props {
|
||||
@event open = function
|
||||
@event close = function
|
||||
size = "default"
|
||||
color = "primary"
|
||||
title = "Tooltip"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ui",
|
||||
"version": "0.4.0",
|
||||
"version": "0.5.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+3668
-14
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user