chore(release): refresh private package staging
Quality / quality (ubuntu-latest) (push) Failing after 14m12s
Quality / quality (windows-latest) (push) Canceled after 0s

This commit is contained in:
2026-08-10 00:55:12 +05:30
parent bca9549f3a
commit db612df6cd
69 changed files with 5421 additions and 7243 deletions
+1
View File
@@ -201,6 +201,7 @@ A file opens with `page <Name>` or `component <Name>` followed by a `{ ... }` bo
- `@event name = function` inside `props` — declares a public component event. Emit it from component behavior with `name(detail)` or `$emit("name", detail)`, and consume it with `<Component @name="handler(event)" />`. - `@event name = function` inside `props` — declares a public component event. Emit it from component behavior with `name(detail)` or `$emit("name", detail)`, and consume it with `<Component @name="handler(event)" />`.
- `state <ident>: Type = <expr>` — typed reactive state seeded from a raw JS expression, including native array and object literals. The annotation is optional for backward compatibility. - `state <ident>: Type = <expr>` — typed reactive state seeded from a raw JS expression, including native array and object literals. The annotation is optional for backward compatibility.
- `view { <html> }` — plain HTML with `{expr}` interpolation in text and attributes, JSX-style component props such as `items={items}`, `items={[...]}`, and `options={{...}}`, hyphenated attributes, boolean attributes, `@event="..."` client bindings, and `<!-- comments -->`. Structured component props are serialized safely for SSR; expressions that reference `state` retain their initial value and update reactively in the browser. - `view { <html> }` — plain HTML with `{expr}` interpolation in text and attributes, JSX-style component props such as `items={items}`, `items={[...]}`, and `options={{...}}`, hyphenated attributes, boolean attributes, `@event="..."` client bindings, and `<!-- comments -->`. Structured component props are serialized safely for SSR; expressions that reference `state` retain their initial value and update reactively in the browser.
- Client functions automatically commit state changed by `setTimeout` callbacks. For other deferred callbacks (observers, third-party APIs, or detached promise callbacks), call the injected `commit()` function after changing local state; returning/awaiting a promise also commits through the normal function boundary.
- `seo { key = "value" ... }` — metadata merged into the generated `meta`. - `seo { key = "value" ... }` — metadata merged into the generated `meta`.
- `style { <raw css> }` — inlined page/component stylesheet (repeatable). - `style { <raw css> }` — inlined page/component stylesheet (repeatable).
- `functions { <TypeScript> }` — helpers with typed parameters and return values. Types remain in server output and are safely erased from browser behavior code. - `functions { <TypeScript> }` — helpers with typed parameters and return values. Types remain in server output and are safely erased from browser behavior code.
+4
View File
@@ -44,6 +44,10 @@
"import": "./dist/redis.js" "import": "./dist/redis.js"
} }
}, },
"dependencies": {
"@wrnexus/core": "^0.8.6",
"@wrnexus/rpc": "^0.8.6"
},
"files": [ "files": [
"dist", "dist",
"README.md" "README.md"
+2 -1
View File
@@ -37,7 +37,8 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.8.6" "@wrnexus/core": "^0.8.6",
"@wrnexus/rpc": "^0.8.6"
}, },
"files": [ "files": [
"dist", "dist",
+9 -63
View File
@@ -1,6 +1,6 @@
# WRNexus UI component reference # WRNexus UI component reference
This reference is generated from the 108 packaged `.wrn` component sources. Props marked required have no default; all others show their runtime default. This reference is generated from the 102 packaged `.wrn` component sources. Props marked required have no default; all others show their runtime default.
## Advanced-forms ## Advanced-forms
@@ -22,15 +22,6 @@ Editable autocomplete combobox with local and remote suggestions.
- Slots: None - Slots: None
- Outputs: `search({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `select({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `change({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `clear({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `open({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `close({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `load({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `error({ error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string)` - Outputs: `search({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `select({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `change({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `clear({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `open({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `close({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `load({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `error({ error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string)`
### CopyMarkup
Theme-aware, responsive copy markup component.
- Mount: `data-component="CopyMarkup"`
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Copy Markup"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "text"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
- Slots: None
- Outputs: `copy({ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])`, `success({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `error({ error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string)`
### InputNumber ### InputNumber
Theme-aware, responsive input number component. Theme-aware, responsive input number component.
@@ -303,23 +294,14 @@ Present responsive chronological activity, milestones, or workflow status with r
- Slots: `default` - Slots: `default`
- Outputs: `select({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })` - Outputs: `select({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`
### Toast
Theme-aware, responsive toast component.
- Mount: `data-component="Toast"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Toast"`, `description: string = ""`, `items: unknown[] = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Outputs: `dismiss({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `action({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`
### TreeView ### TreeView
Theme-aware, responsive tree view component. Theme-aware, responsive tree view component.
- Mount: `data-component="TreeView"` - Mount: `data-component="TreeView"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Tree View"`, `description: string = ""`, `items: unknown[] = []`, `variant: string = "default"`, `class: string = ""` - Props: `title: string = "Tree View"`, `description: string = ""`, `items: unknown[] = []`, `valueKey: string = "value"`, `labelKey: string = "label"`, `defaultExpanded: unknown[] = []`, `selected: string = ""`, `size: string = "default"`, `color: string = "primary"`, `class: string = ""`
- Slots: `default` - Slots: `default`
- Outputs: `select({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `toggle({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `expand({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `collapse({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })` - Outputs: `select({ item: object; value: string; sourceEvent?: Event })`, `toggle({ item: object; value: string; expanded: boolean; sourceEvent?: Event })`, `expand({ item: object; value: string; sourceEvent?: Event })`, `collapse({ item: object; value: string; sourceEvent?: Event })`
## Core ## Core
@@ -509,50 +491,32 @@ Theme-aware, responsive time picker component.
## Integrations ## Integrations
### AdvancedDatePicker
Theme-aware, responsive advanced date picker component.
- Mount: `data-component="AdvancedDatePicker"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Advanced Date Picker"`, `description: string = ""`, `items: unknown[] = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Outputs: `input({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `change({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `open({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `close({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `clear({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`
### AdvancedRangeSlider
Theme-aware, responsive advanced range slider component.
- Mount: `data-component="AdvancedRangeSlider"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Advanced Range Slider"`, `description: string = ""`, `items: unknown[] = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Outputs: `input({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `change({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `start({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `end({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`
### Chart ### Chart
Theme-aware, responsive chart component. Theme-aware, responsive chart component.
- Mount: `data-component="Chart"` - Mount: `data-component="Chart"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Chart"`, `description: string = ""`, `items: unknown[] = []`, `variant: string = "default"`, `class: string = ""` - Props: `title: string = "Chart"`, `description: string = ""`, `items: unknown[] = []`, `valueKey: string = "value"`, `labelKey: string = "label"`, `height: number = 240`, `showLegend: boolean = true`, `showValues: boolean = true`, `size: string = "default"`, `color: string = "primary"`, `variant: string = "bar"`, `class: string = ""`
- Slots: `default` - Slots: `default`
- Outputs: `select({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `dataPointClick({ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])`, `legendToggle({ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])` - Outputs: `select({ item: object; index: number; sourceEvent?: Event })`, `dataPointClick({ item: object; index: number; sourceEvent?: Event })`, `legendToggle({ item: object; index: number; hidden: boolean; sourceEvent?: Event })`
### Clipboard ### Clipboard
Theme-aware, responsive clipboard component. Theme-aware, responsive clipboard component.
- Mount: `data-component="Clipboard"` - Mount: `data-component="Clipboard"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Clipboard"`, `description: string = ""`, `items: unknown[] = []`, `variant: string = "default"`, `class: string = ""` - Props: `value: string = ""`, `label: string = "Copy"`, `copiedLabel: string = "Copied"`, `errorLabel: string = "Copy failed"`, `title: string = "Clipboard"`, `description: string = ""`, `code: boolean = true`, `size: string = "default"`, `color: string = "primary"`, `disabled: boolean = false`, `class: string = ""`
- Slots: `default` - Slots: `default`
- Outputs: `copy({ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])`, `success({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `error({ error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string)` - Outputs: `copy({ value: string; sourceEvent?: Event })`, `success({ value: string; sourceEvent?: Event })`, `error({ error: Error | string; value: string; sourceEvent?: Event })`
### Confetti ### Confetti
Theme-aware, responsive confetti component. Theme-aware, responsive confetti component.
- Mount: `data-component="Confetti"` - Mount: `data-component="Confetti"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Confetti"`, `description: string = ""`, `items: unknown[] = []`, `variant: string = "default"`, `class: string = ""` - Props: `label: string = "Celebrate"`, `duration: number = 1200`, `count: number = 24`, `autoStart: boolean = false`, `disabled: boolean = false`, `size: string = "default"`, `color: string = "primary"`, `class: string = ""`
- Slots: `default` - Slots: `default`
- Outputs: `start({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `complete({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })` - Outputs: `start({ sourceEvent?: Event; duration: number })`, `complete({ sourceEvent?: Event; duration: number })`
### DataMap ### DataMap
@@ -572,15 +536,6 @@ Theme-aware, responsive drag and drop component.
- Slots: `default` - Slots: `default`
- Outputs: `dragStart({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `dragEnd({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `dragEnter({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `dragLeave({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `drop({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `change({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)` - Outputs: `dragStart({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `dragEnd({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `dragEnter({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `dragLeave({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `drop({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `change({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`
### FileUpload
Theme-aware, responsive file upload component.
- Mount: `data-component="FileUpload"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "File Upload"`, `description: string = ""`, `items: unknown[] = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Outputs: `select({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `upload({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `progress({ progress: number; [key: string]: string | number | boolean | null | object } | number)`, `success({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `error({ error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string)`, `cancel({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `remove({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`
### Map ### Map
Present responsive location information and markers with map-ready metadata and movement or marker events. Present responsive location information and markers with map-ready metadata and movement or marker events.
@@ -590,15 +545,6 @@ Present responsive location information and markers with map-ready metadata and
- Slots: `default` - Slots: `default`
- Outputs: `markerClick({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `select({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `zoom({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })` - Outputs: `markerClick({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `select({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `zoom({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`
### ToastNotifications
Theme-aware, responsive toast notifications component.
- Mount: `data-component="ToastNotifications"`
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Toast Notifications"`, `description: string = ""`, `items: unknown[] = []`, `variant: string = "default"`, `class: string = ""`
- Slots: `default`
- Outputs: `add({ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])`, `dismiss({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`, `clear({ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)`, `action({ sourceEvent?: Event; [key: string]: string | number | boolean | null | object })`
### WysiwygEditor ### WysiwygEditor
Theme-aware, responsive wysiwyg editor component. Theme-aware, responsive wysiwyg editor component.
+5 -9
View File
@@ -118,16 +118,12 @@ are `.wrn` files rendered server-side.
The framework serves this stylesheet once at `/__wrnexus/ui.css`, so pages get all The framework serves this stylesheet once at `/__wrnexus/ui.css`, so pages get all
component styles from a single request. component styles from a single request.
### Tailwind and motion ### Component styles and motion
Components use static Tailwind utility classes alongside the shared `.wire-*` Components own their BEM styles in local `style {}` blocks and do not require a
layer. If the package is consumed by a separate Tailwind build, include its Tailwind scan. `ui.css` supplies only global tokens, resets, and shared
component sources so every utility is generated: primitives. Applications can still use Tailwind independently in their own
source files.
```css
@import "tailwindcss";
@source "../node_modules/@wrnexus/ui/components/*.wrn";
```
The shared stylesheet gives all component boundaries consistent, GPU-friendly The shared stylesheet gives all component boundaries consistent, GPU-friendly
entry and interaction motion. Override `--wire-motion-fast`, entry and interaction motion. Override `--wire-motion-fast`,
-30
View File
@@ -6,16 +6,6 @@
"category": "base", "category": "base",
"purpose": "Theme-aware, responsive accordion component." "purpose": "Theme-aware, responsive accordion component."
}, },
{
"name": "AdvancedDatePicker",
"category": "integrations",
"purpose": "Theme-aware, responsive advanced date picker component."
},
{
"name": "AdvancedRangeSlider",
"category": "integrations",
"purpose": "Theme-aware, responsive advanced range slider component."
},
{ {
"name": "AdvancedSelect", "name": "AdvancedSelect",
"category": "advanced-forms", "category": "advanced-forms",
@@ -151,11 +141,6 @@
"category": "overlays", "category": "overlays",
"purpose": "Open an accessible keyboard-aware action menu from pointer or keyboard context interactions." "purpose": "Open an accessible keyboard-aware action menu from pointer or keyboard context interactions."
}, },
{
"name": "CopyMarkup",
"category": "advanced-forms",
"purpose": "Theme-aware, responsive copy markup component."
},
{ {
"name": "CustomScrollbar", "name": "CustomScrollbar",
"category": "layout", "category": "layout",
@@ -221,11 +206,6 @@
"category": "forms", "category": "forms",
"purpose": "Theme-aware, responsive file input component." "purpose": "Theme-aware, responsive file input component."
}, },
{
"name": "FileUpload",
"category": "integrations",
"purpose": "Theme-aware, responsive file upload component."
},
{ {
"name": "FileUploadProgress", "name": "FileUploadProgress",
"category": "base", "category": "base",
@@ -496,16 +476,6 @@
"category": "base", "category": "base",
"purpose": "Present responsive chronological activity, milestones, or workflow status with rich item metadata." "purpose": "Present responsive chronological activity, milestones, or workflow status with rich item metadata."
}, },
{
"name": "Toast",
"category": "base",
"purpose": "Theme-aware, responsive toast component."
},
{
"name": "ToastNotifications",
"category": "integrations",
"purpose": "Theme-aware, responsive toast notifications component."
},
{ {
"name": "Toaster", "name": "Toaster",
"category": "core", "category": "core",
+10 -3
View File
@@ -1,5 +1,12 @@
{ {
"generatedFrom": "full component catalog reset", "generatedFrom": "framework remediation 0.8.7",
"removedCount": 0, "removedCount": 6,
"replacements": {} "replacements": {
"AdvancedDatePicker": "DatePicker",
"AdvancedRangeSlider": "RangeSlider",
"FileUpload": "FileInput",
"Toast": "Toaster",
"ToastNotifications": "Toaster",
"CopyMarkup": "Clipboard"
}
} }
+179 -602
View File
@@ -1,6 +1,6 @@
{ {
"generatedFrom": "packages/ui/components/*.wrn", "generatedFrom": "packages/ui/components/*.wrn",
"count": 108, "count": 102,
"components": [ "components": [
{ {
"name": "Accordion", "name": "Accordion",
@@ -146,166 +146,6 @@
"events": ["change", "open", "close"], "events": ["change", "open", "close"],
"source": "components/Accordion.wrn" "source": "components/Accordion.wrn"
}, },
{
"name": "AdvancedDatePicker",
"mount": "AdvancedDatePicker",
"category": "integrations",
"purpose": "Theme-aware, responsive advanced date picker component.",
"props": [
{
"name": "size",
"type": "string",
"required": false,
"default": "\"default\"",
"options": []
},
{
"name": "color",
"type": "string",
"required": false,
"default": "\"primary\"",
"options": []
},
{
"name": "title",
"type": "string",
"required": false,
"default": "\"Advanced Date Picker\"",
"options": []
},
{
"name": "description",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
},
{
"name": "items",
"type": "unknown[]",
"required": false,
"default": "[]",
"options": []
},
{
"name": "variant",
"type": "string",
"required": false,
"default": "\"default\"",
"options": []
},
{
"name": "class",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
}
],
"slots": ["default"],
"outputs": [
{
"name": "input",
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
},
{
"name": "change",
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
},
{
"name": "open",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
},
{
"name": "close",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
},
{
"name": "clear",
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
}
],
"events": ["input", "change", "open", "close", "clear"],
"source": "components/AdvancedDatePicker.wrn"
},
{
"name": "AdvancedRangeSlider",
"mount": "AdvancedRangeSlider",
"category": "integrations",
"purpose": "Theme-aware, responsive advanced range slider component.",
"props": [
{
"name": "size",
"type": "string",
"required": false,
"default": "\"default\"",
"options": []
},
{
"name": "color",
"type": "string",
"required": false,
"default": "\"primary\"",
"options": []
},
{
"name": "title",
"type": "string",
"required": false,
"default": "\"Advanced Range Slider\"",
"options": []
},
{
"name": "description",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
},
{
"name": "items",
"type": "unknown[]",
"required": false,
"default": "[]",
"options": []
},
{
"name": "variant",
"type": "string",
"required": false,
"default": "\"default\"",
"options": []
},
{
"name": "class",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
}
],
"slots": ["default"],
"outputs": [
{
"name": "input",
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
},
{
"name": "change",
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
},
{
"name": "start",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
},
{
"name": "end",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
}
],
"events": ["input", "change", "start", "end"],
"source": "components/AdvancedRangeSlider.wrn"
},
{ {
"name": "AdvancedSelect", "name": "AdvancedSelect",
"mount": "AdvancedSelect", "mount": "AdvancedSelect",
@@ -1756,7 +1596,7 @@
} }
], ],
"events": ["dismiss"], "events": ["dismiss"],
"source": "components/Badge.wrn" "source": "components/badge.wrn"
}, },
{ {
"name": "Blockquote", "name": "Blockquote",
@@ -2935,7 +2775,7 @@
"dragStart", "dragStart",
"dragEnd" "dragEnd"
], ],
"source": "components/carousel.wrn" "source": "components/Carousel.wrn"
}, },
{ {
"name": "Chart", "name": "Chart",
@@ -2943,20 +2783,6 @@
"category": "integrations", "category": "integrations",
"purpose": "Theme-aware, responsive chart component.", "purpose": "Theme-aware, responsive chart component.",
"props": [ "props": [
{
"name": "size",
"type": "string",
"required": false,
"default": "\"default\"",
"options": []
},
{
"name": "color",
"type": "string",
"required": false,
"default": "\"primary\"",
"options": []
},
{ {
"name": "title", "name": "title",
"type": "string", "type": "string",
@@ -2979,12 +2805,61 @@
"options": [] "options": []
}, },
{ {
"name": "variant", "name": "valueKey",
"type": "string",
"required": false,
"default": "\"value\"",
"options": []
},
{
"name": "labelKey",
"type": "string",
"required": false,
"default": "\"label\"",
"options": []
},
{
"name": "height",
"type": "number",
"required": false,
"default": "240",
"options": []
},
{
"name": "showLegend",
"type": "boolean",
"required": false,
"default": "true",
"options": []
},
{
"name": "showValues",
"type": "boolean",
"required": false,
"default": "true",
"options": []
},
{
"name": "size",
"type": "string", "type": "string",
"required": false, "required": false,
"default": "\"default\"", "default": "\"default\"",
"options": [] "options": []
}, },
{
"name": "color",
"type": "string",
"required": false,
"default": "\"primary\"",
"options": []
},
{
"name": "variant",
"type": "string",
"required": false,
"default": "\"bar\"",
"options": []
},
{ {
"name": "class", "name": "class",
"type": "string", "type": "string",
@@ -2997,15 +2872,15 @@
"outputs": [ "outputs": [
{ {
"name": "select", "name": "select",
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null" "payloadType": "{ item: object; index: number; sourceEvent?: Event }"
}, },
{ {
"name": "dataPointClick", "name": "dataPointClick",
"payloadType": "{ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]" "payloadType": "{ item: object; index: number; sourceEvent?: Event }"
}, },
{ {
"name": "legendToggle", "name": "legendToggle",
"payloadType": "{ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]" "payloadType": "{ item: object; index: number; hidden: boolean; sourceEvent?: Event }"
} }
], ],
"events": ["select", "dataPointClick", "legendToggle"], "events": ["select", "dataPointClick", "legendToggle"],
@@ -3337,7 +3212,7 @@
} }
], ],
"events": ["input", "change", "focus", "blur", "invalid"], "events": ["input", "change", "focus", "blur", "invalid"],
"source": "components/Checkbox.wrn" "source": "components/checkbox.wrn"
}, },
{ {
"name": "Clipboard", "name": "Clipboard",
@@ -3346,17 +3221,31 @@
"purpose": "Theme-aware, responsive clipboard component.", "purpose": "Theme-aware, responsive clipboard component.",
"props": [ "props": [
{ {
"name": "size", "name": "value",
"type": "string", "type": "string",
"required": false, "required": false,
"default": "\"default\"", "default": "\"\"",
"options": [] "options": []
}, },
{ {
"name": "color", "name": "label",
"type": "string", "type": "string",
"required": false, "required": false,
"default": "\"primary\"", "default": "\"Copy\"",
"options": []
},
{
"name": "copiedLabel",
"type": "string",
"required": false,
"default": "\"Copied\"",
"options": []
},
{
"name": "errorLabel",
"type": "string",
"required": false,
"default": "\"Copy failed\"",
"options": [] "options": []
}, },
{ {
@@ -3374,19 +3263,33 @@
"options": [] "options": []
}, },
{ {
"name": "items", "name": "code",
"type": "unknown[]", "type": "boolean",
"required": false, "required": false,
"default": "[]", "default": "true",
"options": [] "options": []
}, },
{ {
"name": "variant", "name": "size",
"type": "string", "type": "string",
"required": false, "required": false,
"default": "\"default\"", "default": "\"default\"",
"options": [] "options": []
}, },
{
"name": "color",
"type": "string",
"required": false,
"default": "\"primary\"",
"options": []
},
{
"name": "disabled",
"type": "boolean",
"required": false,
"default": "false",
"options": []
},
{ {
"name": "class", "name": "class",
"type": "string", "type": "string",
@@ -3399,15 +3302,15 @@
"outputs": [ "outputs": [
{ {
"name": "copy", "name": "copy",
"payloadType": "{ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]" "payloadType": "{ value: string; sourceEvent?: Event }"
}, },
{ {
"name": "success", "name": "success",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" "payloadType": "{ value: string; sourceEvent?: Event }"
}, },
{ {
"name": "error", "name": "error",
"payloadType": "{ error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string" "payloadType": "{ error: Error | string; value: string; sourceEvent?: Event }"
} }
], ],
"events": ["copy", "success", "error"], "events": ["copy", "success", "error"],
@@ -4048,6 +3951,41 @@
"category": "integrations", "category": "integrations",
"purpose": "Theme-aware, responsive confetti component.", "purpose": "Theme-aware, responsive confetti component.",
"props": [ "props": [
{
"name": "label",
"type": "string",
"required": false,
"default": "\"Celebrate\"",
"options": []
},
{
"name": "duration",
"type": "number",
"required": false,
"default": "1200",
"options": []
},
{
"name": "count",
"type": "number",
"required": false,
"default": "24",
"options": []
},
{
"name": "autoStart",
"type": "boolean",
"required": false,
"default": "false",
"options": []
},
{
"name": "disabled",
"type": "boolean",
"required": false,
"default": "false",
"options": []
},
{ {
"name": "size", "name": "size",
"type": "string", "type": "string",
@@ -4062,34 +4000,6 @@
"default": "\"primary\"", "default": "\"primary\"",
"options": [] "options": []
}, },
{
"name": "title",
"type": "string",
"required": false,
"default": "\"Confetti\"",
"options": []
},
{
"name": "description",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
},
{
"name": "items",
"type": "unknown[]",
"required": false,
"default": "[]",
"options": []
},
{
"name": "variant",
"type": "string",
"required": false,
"default": "\"default\"",
"options": []
},
{ {
"name": "class", "name": "class",
"type": "string", "type": "string",
@@ -4102,11 +4012,11 @@
"outputs": [ "outputs": [
{ {
"name": "start", "name": "start",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" "payloadType": "{ sourceEvent?: Event; duration: number }"
}, },
{ {
"name": "complete", "name": "complete",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" "payloadType": "{ sourceEvent?: Event; duration: number }"
} }
], ],
"events": ["start", "complete"], "events": ["start", "complete"],
@@ -4328,122 +4238,6 @@
"events": ["open", "close", "select", "action"], "events": ["open", "close", "select", "action"],
"source": "components/ContextMenu.wrn" "source": "components/ContextMenu.wrn"
}, },
{
"name": "CopyMarkup",
"mount": "CopyMarkup",
"category": "advanced-forms",
"purpose": "Theme-aware, responsive copy markup component.",
"props": [
{
"name": "size",
"type": "string",
"required": false,
"default": "\"default\"",
"options": []
},
{
"name": "color",
"type": "string",
"required": false,
"default": "\"primary\"",
"options": []
},
{
"name": "label",
"type": "string",
"required": false,
"default": "\"Copy Markup\"",
"options": []
},
{
"name": "name",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
},
{
"name": "value",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
},
{
"name": "placeholder",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
},
{
"name": "type",
"type": "string",
"required": false,
"default": "\"text\"",
"options": []
},
{
"name": "min",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
},
{
"name": "max",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
},
{
"name": "step",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
},
{
"name": "disabled",
"type": "boolean",
"required": false,
"default": "false",
"options": []
},
{
"name": "required",
"type": "boolean",
"required": false,
"default": "false",
"options": []
},
{
"name": "class",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
}
],
"slots": [],
"outputs": [
{
"name": "copy",
"payloadType": "{ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]"
},
{
"name": "success",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
},
{
"name": "error",
"payloadType": "{ error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string"
}
],
"events": ["copy", "success", "error"],
"source": "components/CopyMarkup.wrn"
},
{ {
"name": "CustomScrollbar", "name": "CustomScrollbar",
"mount": "CustomScrollbar", "mount": "CustomScrollbar",
@@ -6240,96 +6034,6 @@
"events": ["input", "change", "focus", "blur", "select", "clear", "invalid"], "events": ["input", "change", "focus", "blur", "select", "clear", "invalid"],
"source": "components/FileInput.wrn" "source": "components/FileInput.wrn"
}, },
{
"name": "FileUpload",
"mount": "FileUpload",
"category": "integrations",
"purpose": "Theme-aware, responsive file upload component.",
"props": [
{
"name": "size",
"type": "string",
"required": false,
"default": "\"default\"",
"options": []
},
{
"name": "color",
"type": "string",
"required": false,
"default": "\"primary\"",
"options": []
},
{
"name": "title",
"type": "string",
"required": false,
"default": "\"File Upload\"",
"options": []
},
{
"name": "description",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
},
{
"name": "items",
"type": "unknown[]",
"required": false,
"default": "[]",
"options": []
},
{
"name": "variant",
"type": "string",
"required": false,
"default": "\"default\"",
"options": []
},
{
"name": "class",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
}
],
"slots": ["default"],
"outputs": [
{
"name": "select",
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
},
{
"name": "upload",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
},
{
"name": "progress",
"payloadType": "{ progress: number; [key: string]: string | number | boolean | null | object } | number"
},
{
"name": "success",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
},
{
"name": "error",
"payloadType": "{ error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string"
},
{
"name": "cancel",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
},
{
"name": "remove",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
}
],
"events": ["select", "upload", "progress", "success", "error", "cancel", "remove"],
"source": "components/FileUpload.wrn"
},
{ {
"name": "FileUploadProgress", "name": "FileUploadProgress",
"mount": "FileUploadProgress", "mount": "FileUploadProgress",
@@ -7247,7 +6951,7 @@
} }
], ],
"events": ["input", "change", "focus", "blur", "invalid", "keydown", "keyup"], "events": ["input", "change", "focus", "blur", "invalid", "keydown", "keyup"],
"source": "components/Input.wrn" "source": "components/input.wrn"
}, },
{ {
"name": "InputGroup", "name": "InputGroup",
@@ -10490,7 +10194,7 @@
} }
], ],
"events": ["input", "change", "focus", "blur", "invalid"], "events": ["input", "change", "focus", "blur", "invalid"],
"source": "components/Radio.wrn" "source": "components/radio.wrn"
}, },
{ {
"name": "RangeSlider", "name": "RangeSlider",
@@ -11308,7 +11012,7 @@
} }
], ],
"events": ["input", "change", "focus", "blur", "open", "close", "invalid"], "events": ["input", "change", "focus", "blur", "open", "close", "invalid"],
"source": "components/Select.wrn" "source": "components/select.wrn"
}, },
{ {
"name": "Sidebar", "name": "Sidebar",
@@ -12387,7 +12091,7 @@
} }
], ],
"events": ["input", "change", "focus", "blur"], "events": ["input", "change", "focus", "blur"],
"source": "components/Switch.wrn" "source": "components/switch.wrn"
}, },
{ {
"name": "Tabs", "name": "Tabs",
@@ -12788,7 +12492,7 @@
} }
], ],
"events": ["input", "change", "focus", "blur", "invalid"], "events": ["input", "change", "focus", "blur", "invalid"],
"source": "components/Textarea.wrn" "source": "components/textarea.wrn"
}, },
{ {
"name": "TimePicker", "name": "TimePicker",
@@ -13079,154 +12783,6 @@
"events": ["select"], "events": ["select"],
"source": "components/Timeline.wrn" "source": "components/Timeline.wrn"
}, },
{
"name": "Toast",
"mount": "Toast",
"category": "base",
"purpose": "Theme-aware, responsive toast component.",
"props": [
{
"name": "size",
"type": "string",
"required": false,
"default": "\"default\"",
"options": []
},
{
"name": "color",
"type": "string",
"required": false,
"default": "\"primary\"",
"options": []
},
{
"name": "title",
"type": "string",
"required": false,
"default": "\"Toast\"",
"options": []
},
{
"name": "description",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
},
{
"name": "items",
"type": "unknown[]",
"required": false,
"default": "[]",
"options": []
},
{
"name": "variant",
"type": "string",
"required": false,
"default": "\"default\"",
"options": []
},
{
"name": "class",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
}
],
"slots": ["default"],
"outputs": [
{
"name": "dismiss",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
},
{
"name": "action",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
}
],
"events": ["dismiss", "action"],
"source": "components/Toast.wrn"
},
{
"name": "ToastNotifications",
"mount": "ToastNotifications",
"category": "integrations",
"purpose": "Theme-aware, responsive toast notifications component.",
"props": [
{
"name": "size",
"type": "string",
"required": false,
"default": "\"default\"",
"options": []
},
{
"name": "color",
"type": "string",
"required": false,
"default": "\"primary\"",
"options": []
},
{
"name": "title",
"type": "string",
"required": false,
"default": "\"Toast Notifications\"",
"options": []
},
{
"name": "description",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
},
{
"name": "items",
"type": "unknown[]",
"required": false,
"default": "[]",
"options": []
},
{
"name": "variant",
"type": "string",
"required": false,
"default": "\"default\"",
"options": []
},
{
"name": "class",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
}
],
"slots": ["default"],
"outputs": [
{
"name": "add",
"payloadType": "{ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]"
},
{
"name": "dismiss",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
},
{
"name": "clear",
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null"
},
{
"name": "action",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }"
}
],
"events": ["add", "dismiss", "clear", "action"],
"source": "components/ToastNotifications.wrn"
},
{ {
"name": "Toaster", "name": "Toaster",
"mount": "Toaster", "mount": "Toaster",
@@ -13874,7 +13430,7 @@
} }
], ],
"events": ["toggle", "open", "close"], "events": ["toggle", "open", "close"],
"source": "components/Tooltip.wrn" "source": "components/tooltip.wrn"
}, },
{ {
"name": "TreeView", "name": "TreeView",
@@ -13882,20 +13438,6 @@
"category": "base", "category": "base",
"purpose": "Theme-aware, responsive tree view component.", "purpose": "Theme-aware, responsive tree view component.",
"props": [ "props": [
{
"name": "size",
"type": "string",
"required": false,
"default": "\"default\"",
"options": []
},
{
"name": "color",
"type": "string",
"required": false,
"default": "\"primary\"",
"options": []
},
{ {
"name": "title", "name": "title",
"type": "string", "type": "string",
@@ -13918,12 +13460,47 @@
"options": [] "options": []
}, },
{ {
"name": "variant", "name": "valueKey",
"type": "string",
"required": false,
"default": "\"value\"",
"options": []
},
{
"name": "labelKey",
"type": "string",
"required": false,
"default": "\"label\"",
"options": []
},
{
"name": "defaultExpanded",
"type": "unknown[]",
"required": false,
"default": "[]",
"options": []
},
{
"name": "selected",
"type": "string",
"required": false,
"default": "\"\"",
"options": []
},
{
"name": "size",
"type": "string", "type": "string",
"required": false, "required": false,
"default": "\"default\"", "default": "\"default\"",
"options": [] "options": []
}, },
{
"name": "color",
"type": "string",
"required": false,
"default": "\"primary\"",
"options": []
},
{ {
"name": "class", "name": "class",
"type": "string", "type": "string",
@@ -13936,19 +13513,19 @@
"outputs": [ "outputs": [
{ {
"name": "select", "name": "select",
"payloadType": "{ value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null" "payloadType": "{ item: object; value: string; sourceEvent?: Event }"
}, },
{ {
"name": "toggle", "name": "toggle",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" "payloadType": "{ item: object; value: string; expanded: boolean; sourceEvent?: Event }"
}, },
{ {
"name": "expand", "name": "expand",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" "payloadType": "{ item: object; value: string; sourceEvent?: Event }"
}, },
{ {
"name": "collapse", "name": "collapse",
"payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" "payloadType": "{ item: object; value: string; sourceEvent?: Event }"
} }
], ],
"events": ["select", "toggle", "expand", "collapse"], "events": ["select", "toggle", "expand", "collapse"],
+205 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Accordion { component Accordion {
outputs { outputs {
change(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) change(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -103,7 +105,7 @@ component Accordion {
data-variant="{variant}" data-variant="{variant}"
data-indicator="{indicator}" data-indicator="{indicator}"
data-multiple="{allowsMultiple() ? 'true' : 'false'}" 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}" class="wire-component wire-component--color-{color} wire-component--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} {#each items as item, index}
<section <section
@@ -204,5 +206,207 @@ component Accordion {
</section> </section>
{/each} {/each}
</div> </div>
<ComponentBaseStyles hidden />
}
style {
.wire-next--accordion {
--wire-accordion-accent: var(--wire-component-color);
display: grid;
width: 100%;
color: var(--wire-color-text);
}
.wire-next__accordion-item {
min-width: 0;
}
.wire-next__accordion-heading {
margin: 0;
font: inherit;
}
.wire-next__accordion-heading > button {
display: flex;
width: 100%;
align-items: center;
gap: 0.75rem;
padding: 0.85rem 0;
border: 0;
background: transparent;
color: var(--wire-color-text);
font: inherit;
font-size: 0.88rem;
font-weight: 700;
text-align: left;
cursor: pointer;
}
.wire-next__accordion-heading > button > span:not(.wire-next__accordion-indicator) {
min-width: 0;
flex: 1;
}
.wire-next__accordion-heading > button:focus-visible {
border-radius: var(--wire-radius-sm);
outline: 2px solid var(--wire-accordion-accent);
outline-offset: 2px;
}
.wire-next__accordion-heading > button:disabled {
cursor: not-allowed;
opacity: 0.5;
}
.wire-next__accordion-indicator {
display: inline-flex;
width: 1rem;
height: 1rem;
flex: 0 0 1rem;
align-items: center;
justify-content: center;
color: var(--wire-color-muted);
font-size: 1rem;
font-weight: 500;
line-height: 1;
transition:
color var(--wire-motion-fast) var(--wire-ease-standard),
transform var(--wire-motion-fast) var(--wire-ease-standard);
}
.wire-next__accordion-indicator > span {
display: inline-flex;
align-items: center;
justify-content: center;
}
.wire-next__accordion-indicator > [class*="icon-["] {
width: 0.95rem;
height: 0.95rem;
}
.wire-next__accordion-item[data-open="true"]
> .wire-next__accordion-heading
.wire-next__accordion-indicator {
color: var(--wire-accordion-accent);
transform: rotate(45deg);
}
.wire-next--accordion[data-indicator="chevron"]
.wire-next__accordion-item[data-open="true"]
> .wire-next__accordion-heading
.wire-next__accordion-indicator {
transform: rotate(180deg);
}
.wire-next__accordion-item[data-open="true"] > .wire-next__accordion-heading > button {
color: var(--wire-accordion-accent);
}
.wire-next__accordion-panel {
display: grid;
grid-template-rows: 0fr;
opacity: 0;
transition:
grid-template-rows var(--wire-motion-base) var(--wire-ease-standard),
opacity var(--wire-motion-fast) var(--wire-ease-standard);
}
.wire-next__accordion-item[data-open="true"] > .wire-next__accordion-panel {
grid-template-rows: 1fr;
opacity: 1;
}
.wire-next__accordion-panel > div {
overflow: hidden;
}
.wire-next__accordion-content {
padding: 0 0 1rem 1.75rem;
color: var(--wire-color-muted);
font-size: 0.86rem;
line-height: 1.65;
}
.wire-next__accordion-content > p {
color: inherit;
}
.wire-next__accordion-content-italic > p::first-line {
font-style: italic;
}
.wire-next__accordion-nested {
display: grid;
margin-top: 0.5rem;
}
.wire-next__accordion-nested .wire-next__accordion-content {
padding-left: 1.5rem;
}
.wire-next--accordion-bordered {
overflow: hidden;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-md);
background: var(--wire-color-surface);
}
.wire-next--accordion-bordered > .wire-next__accordion-item + .wire-next__accordion-item {
border-top: 1px solid var(--wire-color-border);
}
.wire-next--accordion-bordered
> .wire-next__accordion-item
> .wire-next__accordion-heading
> button {
padding-inline: 1rem;
}
.wire-next--accordion-bordered
> .wire-next__accordion-item
> .wire-next__accordion-panel
.wire-next__accordion-content {
padding-inline: 1rem;
}
.wire-next--accordion-separated {
gap: 0.5rem;
}
.wire-next--accordion-separated > .wire-next__accordion-item {
overflow: hidden;
border: 1px solid transparent;
border-radius: var(--wire-radius-md);
background: var(--wire-color-surface-2);
}
.wire-next--accordion-separated > .wire-next__accordion-item[data-open="true"] {
border-color: var(--wire-color-border);
}
.wire-next--accordion-separated
> .wire-next__accordion-item
> .wire-next__accordion-heading
> button,
.wire-next--accordion-separated
> .wire-next__accordion-item
> .wire-next__accordion-panel
.wire-next__accordion-content {
padding-inline: 1rem;
}
.wire-next--accordion-flush {
border-radius: 0;
background: transparent;
box-shadow: none;
}
@media (prefers-reduced-motion: reduce) {
.wire-next__accordion-panel,
.wire-next__accordion-indicator {
transition: none;
}
}
} }
} }
@@ -1,27 +0,0 @@
component AdvancedDatePicker {
outputs {
input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
change(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
open(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
close(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
clear(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
}
props {
size: string = "default"
color: string = "primary"
title: string = "Advanced Date Picker"
description: string = ""
items: unknown[] = []
variant: string = "default"
class: string = ""
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--advanced-date-picker 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>
}
}
@@ -1,26 +0,0 @@
component AdvancedRangeSlider {
outputs {
input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
change(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
start(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
end(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
}
props {
size: string = "default"
color: string = "primary"
title: string = "Advanced Range Slider"
description: string = ""
items: unknown[] = []
variant: string = "default"
class: string = ""
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--advanced-range-slider 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>
}
}
+64 -1
View File
@@ -1,3 +1,7 @@
import SelectStyles from "../styles/SelectStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component AdvancedSelect { component AdvancedSelect {
outputs { outputs {
search(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) search(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -253,7 +257,7 @@ component AdvancedSelect {
view { view {
<div <div
class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--advanced-select {open ? 'wire-next--open' : ''} {fixed ? 'wire-next--advanced-select-fixed' : ''} {invalid ? 'wire-next--invalid' : ''} {disabled ? 'wire-next--disabled' : ''} {class}" class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--advanced-select {open ? 'wire-next--open' : ''} {fixed ? 'wire-next--advanced-select-fixed' : ''} {invalid ? 'wire-next--invalid' : ''} {disabled ? 'wire-next--disabled' : ''} {class}"
data-placement="{placement}" data-placement="{placement}"
data-search-mode="{searchMode}" data-search-mode="{searchMode}"
data-remote="{remote ? 'true' : 'false'}" data-remote="{remote ? 'true' : 'false'}"
@@ -455,5 +459,64 @@ component AdvancedSelect {
data-error="{name}" data-error="{name}"
>{validationMessage}</small> >{validationMessage}</small>
</div> </div>
<SelectStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next__row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
.wire-next__select-search {
position: relative;
display: block;
}
.wire-next__select-search input {
padding-left: 2.25em;
}
.wire-next__select-tags {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
}
.wire-next__select-tags > span {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.3rem 0.55rem;
border-radius: 999px;
color: var(--wire-component-color);
background: color-mix(in srgb, var(--wire-component-color) 12%, transparent);
font-size: 0.75em;
font-weight: 700;
}
.wire-next__select-tags img {
width: 1.25rem;
height: 1.25rem;
border-radius: 50%;
object-fit: cover;
}
.wire-next__select-value {
display: flex;
min-width: 0;
align-items: center;
gap: 0.55em;
}
.wire-next__placeholder {
overflow: hidden;
color: var(--wire-color-muted);
text-overflow: ellipsis;
white-space: nowrap;
}
} }
} }
+210 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component AvatarGroup { component AvatarGroup {
outputs { outputs {
overflow(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]) overflow(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])
@@ -43,7 +45,7 @@ component AvatarGroup {
view { view {
<div <div
{...attrs} {...attrs}
class="wire-next wire-next--avatar-group {class}" class="wire-component wire-next--avatar-group {class}"
data-wrn-avatar-group data-wrn-avatar-group
data-layout="{layout}" data-layout="{layout}"
data-shape="{shape}" data-shape="{shape}"
@@ -146,5 +148,212 @@ component AvatarGroup {
{/if} {/if}
</div> </div>
</div> </div>
<ComponentBaseStyles hidden />
}
style {
/* --- Avatar group -------------------------------------------------------- */
.wire-next--avatar-group {
--wire-avatar-group-size: 3rem;
position: relative;
display: inline-flex;
width: fit-content;
max-width: 100%;
}
.wire-next--avatar-group[data-size="xs"] {
--wire-avatar-group-size: 1.75rem;
}
.wire-next--avatar-group[data-size="sm"] {
--wire-avatar-group-size: 2.25rem;
}
.wire-next--avatar-group[data-size="md"],
.wire-next--avatar-group[data-size="default"] {
--wire-avatar-group-size: 3rem;
}
.wire-next--avatar-group[data-size="lg"] {
--wire-avatar-group-size: 4rem;
}
.wire-next--avatar-group[data-size="xl"] {
--wire-avatar-group-size: 5rem;
}
.wire-next__avatar-group-members {
display: flex;
align-items: center;
}
.wire-next--avatar-group[data-layout="stack"] .wire-next__avatar-group-member,
.wire-next--avatar-group[data-layout="stack"] .wire-next__avatar-group-overflow {
margin-left: calc(var(--wire-avatar-group-size) * -0.22);
}
.wire-next--avatar-group[data-layout="stack"] :first-child {
margin-left: 0;
}
.wire-next--avatar-group[data-layout="grid"] .wire-next__avatar-group-members {
display: grid;
grid-template-columns: repeat(var(--wire-avatar-group-columns), var(--wire-avatar-group-size));
gap: 0.65rem;
}
.wire-next__avatar-group-member,
.wire-next__avatar-group-overflow {
--wire-avatar-group-color: var(--wire-color-primary);
position: relative;
display: inline-grid;
width: var(--wire-avatar-group-size);
height: var(--wire-avatar-group-size);
flex: none;
place-items: center;
border-radius: 999px;
outline: none;
transition:
z-index var(--wire-motion-fast),
transform var(--wire-motion-base) var(--wire-ease-emphasized);
}
.wire-next__avatar-group-member[data-color="secondary"] {
--wire-avatar-group-color: #737373;
}
.wire-next__avatar-group-member[data-color="success"] {
--wire-avatar-group-color: var(--wire-color-success);
}
.wire-next__avatar-group-member[data-color="info"] {
--wire-avatar-group-color: var(--wire-color-info);
}
.wire-next__avatar-group-member[data-color="warning"] {
--wire-avatar-group-color: var(--wire-color-warning);
}
.wire-next__avatar-group-member[data-color="danger"] {
--wire-avatar-group-color: var(--wire-color-danger);
}
.wire-next__avatar-group-member[data-shape="rounded"] {
border-radius: calc(var(--wire-radius-sm, 0.5rem) * 0.72);
}
.wire-next__avatar-group-avatar,
.wire-next__avatar-group-overflow-button {
display: grid;
width: 100%;
height: 100%;
overflow: hidden;
place-items: center;
color: white;
border: 2px solid var(--wire-avatar-group-ring);
border-radius: inherit;
background: var(--wire-avatar-group-color, var(--wire-color-primary));
box-shadow: 0 5px 14px rgb(0 0 0 / 0.16);
font: inherit;
font-size: calc(var(--wire-avatar-group-size) * 0.3);
font-weight: 800;
}
.wire-next__avatar-group-avatar img,
.wire-next__avatar-group-menu-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.wire-next__avatar-group-overflow-button {
cursor: pointer;
color: var(--wire-color-text);
background: var(--wire-color-surface-2);
}
.wire-next__avatar-group-member:hover,
.wire-next__avatar-group-member:focus-visible,
.wire-next__avatar-group-overflow:focus-within {
z-index: 5;
transform: translateY(-3px);
}
.wire-next__avatar-group-member:focus-visible,
.wire-next__avatar-group-overflow-button:focus-visible {
outline: 2px solid var(--wire-color-primary);
outline-offset: 3px;
}
.wire-next__avatar-group-tooltip {
position: absolute;
left: 50%;
bottom: calc(100% + 0.65rem);
z-index: 20;
width: max-content;
max-width: 14rem;
padding: 0.4rem 0.6rem;
color: var(--wire-color-bg);
border-radius: 0.4rem;
background: var(--wire-color-text);
box-shadow: 0 8px 22px rgb(0 0 0 / 0.22);
font-size: 0.75rem;
font-weight: 650;
pointer-events: none;
opacity: 0;
transform: translate(-50%, 0.25rem);
transition:
opacity var(--wire-motion-fast),
transform var(--wire-motion-fast);
}
.wire-next__avatar-group-member:hover .wire-next__avatar-group-tooltip,
.wire-next__avatar-group-member:focus-visible .wire-next__avatar-group-tooltip {
opacity: 1;
transform: translate(-50%, 0);
}
.wire-next__avatar-group-menu {
position: absolute;
top: calc(100% + 0.65rem);
right: 0;
z-index: 30;
display: grid;
width: max-content;
min-width: 12rem;
gap: 0.25rem;
padding: 0.45rem;
color: var(--wire-color-text);
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-sm, 0.5rem);
background: var(--wire-color-surface);
box-shadow: 0 16px 38px rgb(0 0 0 / 0.22);
}
.wire-next__avatar-group-menu-item {
display: flex;
align-items: center;
gap: 0.6rem;
padding: 0.45rem 0.55rem;
border-radius: 0.4rem;
font-size: 0.82rem;
}
.wire-next__avatar-group-menu-item:hover {
background: var(--wire-color-surface-2);
}
.wire-next__avatar-group-menu-avatar {
display: grid;
width: 1.75rem;
height: 1.75rem;
overflow: hidden;
flex: none;
place-items: center;
border-radius: 999px;
background: var(--wire-color-surface-2);
font-size: 0.65rem;
font-weight: 800;
}
} }
} }
+207 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Blockquote { component Blockquote {
props { 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." quote: string = "I just wanted to say that I'm very happy with my purchase so far. The documentation is outstanding - clear and detailed."
@@ -18,7 +20,7 @@ component Blockquote {
view { view {
<figure <figure
{...attrs} {...attrs}
class="wire-next wire-next--blockquote wire-next--color-{color} wire-next--size-{size} {class}" class="wire-component wire-next--blockquote wire-component--color-{color} wire-component--size-{size} {class}"
data-size="{size}" data-size="{size}"
data-color="{color}" data-color="{color}"
data-align="{align}" data-align="{align}"
@@ -63,5 +65,209 @@ component Blockquote {
</figcaption> </figcaption>
{/if} {/if}
</figure> </figure>
<ComponentBaseStyles hidden />
}
style {
.wire-next--blockquote {
--wire-blockquote-color: var(--wire-component-color, var(--wire-color-primary));
--wire-blockquote-font-size: 1.125rem;
--wire-blockquote-mark-size: 4.25rem;
display: grid;
gap: 1.25rem;
width: 100%;
color: var(--wire-color-text);
text-align: left;
}
.wire-next--blockquote[data-size="xs"] {
--wire-blockquote-font-size: 0.875rem;
--wire-blockquote-mark-size: 3rem;
}
.wire-next--blockquote[data-size="sm"] {
--wire-blockquote-font-size: 1rem;
--wire-blockquote-mark-size: 3.5rem;
}
.wire-next--blockquote[data-size="md"],
.wire-next--blockquote[data-size="default"] {
--wire-blockquote-font-size: 1.125rem;
}
.wire-next--blockquote[data-size="lg"] {
--wire-blockquote-font-size: clamp(1.35rem, 2.4vw, 1.75rem);
--wire-blockquote-mark-size: 5rem;
}
.wire-next--blockquote[data-size="xl"] {
--wire-blockquote-font-size: clamp(1.65rem, 3vw, 2.25rem);
--wire-blockquote-mark-size: 5.75rem;
}
.wire-next--blockquote > blockquote {
position: relative;
display: block;
min-width: 0;
margin: 0;
padding-top: calc(var(--wire-blockquote-mark-size) * 0.78);
}
.wire-next__blockquote-mark {
position: absolute;
top: 0;
inset-inline: 0;
display: block;
width: 100%;
color: color-mix(in srgb, var(--wire-blockquote-color) 28%, var(--wire-color-text));
font-family: Georgia, "Times New Roman", serif;
font-size: var(--wire-blockquote-mark-size);
font-style: normal;
font-weight: 700;
line-height: 0.8;
text-align: start;
user-select: none;
}
.wire-next__blockquote-copy {
min-width: 0;
font-family: Georgia, "Times New Roman", serif;
font-size: var(--wire-blockquote-font-size);
line-height: 1.55;
text-wrap: pretty;
}
.wire-next--blockquote[data-italic="true"] .wire-next__blockquote-copy {
font-style: italic;
}
.wire-next__blockquote-copy > :first-child {
margin-top: 0;
}
.wire-next__blockquote-copy > :last-child {
margin-bottom: 0;
}
.wire-next__blockquote-citation {
display: inline-flex;
gap: 0.75rem;
align-items: center;
width: fit-content;
margin-inline-start: 0;
color: var(--wire-color-muted);
font-size: 0.875rem;
line-height: 1.35;
}
.wire-next__blockquote-avatar {
width: 2.5rem;
height: 2.5rem;
flex: 0 0 auto;
border: 2px solid color-mix(in srgb, var(--wire-blockquote-color) 35%, transparent);
border-radius: 999px;
object-fit: cover;
}
.wire-next__blockquote-attribution {
display: grid;
gap: 0.15rem;
}
.wire-next__blockquote-attribution cite {
color: var(--wire-color-text);
font-style: normal;
font-weight: 700;
}
.wire-next__blockquote-attribution a {
color: inherit;
text-decoration-color: color-mix(in srgb, var(--wire-blockquote-color) 55%, transparent);
text-underline-offset: 0.2em;
}
.wire-next__blockquote-attribution a:hover {
color: var(--wire-blockquote-color);
}
.wire-next--blockquote[data-align="center"] {
text-align: center;
}
.wire-next--blockquote[data-align="right"],
.wire-next--blockquote[data-align="end"] {
text-align: right;
}
.wire-next--blockquote[data-align="center"] > blockquote,
.wire-next--blockquote[data-align="right"] > blockquote,
.wire-next--blockquote[data-align="end"] > blockquote {
text-align: inherit;
}
.wire-next--blockquote[data-align="center"] .wire-next__blockquote-mark {
text-align: center;
}
.wire-next--blockquote[data-align="right"] .wire-next__blockquote-mark,
.wire-next--blockquote[data-align="end"] .wire-next__blockquote-mark {
text-align: end;
}
.wire-next--blockquote[data-align="center"] .wire-next__blockquote-citation {
margin-inline: auto;
}
.wire-next--blockquote[data-align="right"] .wire-next__blockquote-citation,
.wire-next--blockquote[data-align="end"] .wire-next__blockquote-citation {
margin-inline-start: auto;
}
.wire-next--blockquote[data-variant="bordered"],
.wire-next--blockquote[data-variant="border"],
.wire-next--blockquote[data-variant="left-border"] {
padding-inline-start: 1.5rem;
border-inline-start: 4px solid var(--wire-blockquote-color);
}
.wire-next--blockquote[data-variant="bordered"] .wire-next__blockquote-mark,
.wire-next--blockquote[data-variant="border"] .wire-next__blockquote-mark,
.wire-next--blockquote[data-variant="left-border"] .wire-next__blockquote-mark {
display: none;
}
.wire-next--blockquote[data-variant="bordered"] > blockquote,
.wire-next--blockquote[data-variant="border"] > blockquote,
.wire-next--blockquote[data-variant="left-border"] > blockquote {
display: block;
padding-top: 0;
}
.wire-next--blockquote[data-variant="bordered"] .wire-next__blockquote-copy,
.wire-next--blockquote[data-variant="border"] .wire-next__blockquote-copy,
.wire-next--blockquote[data-variant="left-border"] .wire-next__blockquote-copy {
padding-top: 0;
}
.wire-next--blockquote[data-variant="bordered"] .wire-next__blockquote-citation,
.wire-next--blockquote[data-variant="border"] .wire-next__blockquote-citation,
.wire-next--blockquote[data-variant="left-border"] .wire-next__blockquote-citation {
margin-inline-start: 0;
}
@media (max-width: 480px) {
.wire-next--blockquote {
--wire-blockquote-mark-size: 3.25rem;
--wire-blockquote-font-size: 1rem;
gap: 1rem;
}
.wire-next--blockquote[data-size="lg"],
.wire-next--blockquote[data-size="xl"] {
--wire-blockquote-font-size: 1.25rem;
}
.wire-next__blockquote-citation {
margin-inline-start: 0;
}
}
} }
} }
+148 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component ButtonGroup { component ButtonGroup {
outputs { outputs {
click(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) click(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
@@ -54,7 +56,7 @@ items: unknown[] = []
view { view {
<div <div
{...attrs} {...attrs}
class="wire-next wire-next--button-group {class}" class="wire-component wire-next--button-group {class}"
role="{toolbar ? 'toolbar' : 'group'}" role="{toolbar ? 'toolbar' : 'group'}"
aria-label="{ariaLabel}" aria-label="{ariaLabel}"
aria-orientation="{orientation}" aria-orientation="{orientation}"
@@ -88,5 +90,150 @@ items: unknown[] = []
{/if} {/if}
<slot /> <slot />
</div> </div>
<ComponentBaseStyles hidden />
}
style {
.wire-next--button-group {
display: inline-flex;
align-items: stretch;
width: fit-content;
max-width: 100%;
isolation: isolate;
}
.wire-next--button-group[data-orientation="vertical"] {
flex-direction: column;
}
.wire-next--button-group[data-attached="false"] {
gap: 0.5rem;
}
.wire-next--button-group[data-disabled="true"] {
cursor: not-allowed;
opacity: 0.6;
}
.wire-next--button-group[data-attached="true"] > :is(.wire-btn, .wire-action) {
position: relative;
margin: 0;
}
.wire-next--button-group[data-attached="true"] > .wire-action {
display: flex;
}
.wire-next--button-group[data-attached="true"] > :is(.wire-btn, .wire-action) :is(.wire-btn) {
height: 100%;
}
.wire-next--button-group[data-attached="true"][data-orientation="horizontal"]
> :is(.wire-btn, .wire-action):not(:first-child) {
margin-inline-start: -1px;
}
.wire-next--button-group[data-attached="true"][data-orientation="horizontal"]
> .wire-btn:not(:first-child):not(:last-child),
.wire-next--button-group[data-attached="true"][data-orientation="horizontal"]
> .wire-action:not(:first-child):not(:last-child)
> .wire-btn {
border-radius: 0;
}
.wire-next--button-group[data-attached="true"][data-orientation="horizontal"]
> .wire-btn:first-child:not(:last-child),
.wire-next--button-group[data-attached="true"][data-orientation="horizontal"]
> .wire-action:first-child:not(:last-child)
> .wire-btn {
border-start-end-radius: 0;
border-end-end-radius: 0;
}
.wire-next--button-group[data-attached="true"][data-orientation="horizontal"]
> .wire-btn:last-child:not(:first-child),
.wire-next--button-group[data-attached="true"][data-orientation="horizontal"]
> .wire-action:last-child:not(:first-child)
> .wire-btn {
border-start-start-radius: 0;
border-end-start-radius: 0;
}
.wire-next--button-group[data-attached="true"][data-orientation="vertical"]
> :is(.wire-btn, .wire-action):not(:first-child) {
margin-top: -1px;
}
.wire-next--button-group[data-attached="true"][data-orientation="vertical"]
> .wire-btn:not(:first-child):not(:last-child),
.wire-next--button-group[data-attached="true"][data-orientation="vertical"]
> .wire-action:not(:first-child):not(:last-child)
> .wire-btn {
border-radius: 0;
}
.wire-next--button-group[data-attached="true"][data-orientation="vertical"]
> .wire-btn:first-child:not(:last-child),
.wire-next--button-group[data-attached="true"][data-orientation="vertical"]
> .wire-action:first-child:not(:last-child)
> .wire-btn {
border-end-start-radius: 0;
border-end-end-radius: 0;
}
.wire-next--button-group[data-attached="true"][data-orientation="vertical"]
> .wire-btn:last-child:not(:first-child),
.wire-next--button-group[data-attached="true"][data-orientation="vertical"]
> .wire-action:last-child:not(:first-child)
> .wire-btn {
border-start-start-radius: 0;
border-start-end-radius: 0;
}
.wire-next--button-group > :is(.wire-btn, .wire-action):focus-within,
.wire-next--button-group > .wire-btn:focus-visible {
z-index: 2;
}
.wire-next--button-group[data-selectable="true"] > .wire-btn[data-selected="true"] {
z-index: 1;
border-color: var(--wire-component-color);
background: color-mix(in srgb, var(--wire-component-color) 16%, var(--wire-color-surface));
color: var(--wire-component-color);
}
@media (max-width: 480px) {
.wire-next--button-group[data-responsive="true"] > :is(.wire-btn, .wire-action) {
display: flex;
width: 100%;
flex-direction: column;
}
.wire-next--button-group[data-responsive="true"] > .wire-action > .wire-btn {
width: 100%;
}
.wire-next--button-group[data-responsive="true"][data-attached="true"]
> :is(.wire-btn, .wire-action) {
margin-top: -1px;
margin-inline-start: 0;
}
.wire-next--button-group[data-responsive="true"][data-attached="true"]
> :is(.wire-btn, .wire-action):first-child {
margin-top: 0;
}
.wire-next--button-group[data-responsive="true"][data-attached="true"] > .wire-btn,
.wire-next--button-group[data-responsive="true"][data-attached="true"]
> .wire-action
> .wire-btn {
border-radius: 0;
}
.wire-next--button-group[data-responsive="true"][data-attached="true"] > .wire-btn:first-child,
.wire-next--button-group[data-responsive="true"][data-attached="true"]
> .wire-action:first-child
> .wire-btn {
border-start-start-radius: var(--wire-radius-sm);
border-start-end-radius: var(--wire-radius-sm);
}
.wire-next--button-group[data-responsive="true"][data-attached="true"] > .wire-btn:last-child,
.wire-next--button-group[data-responsive="true"][data-attached="true"]
> .wire-action:last-child
> .wire-btn {
border-end-start-radius: var(--wire-radius-sm);
border-end-end-radius: var(--wire-radius-sm);
}
}
} }
} }
+369 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
// Interactive, hydration-safe content carousel. // Interactive, hydration-safe content carousel.
component Carousel { component Carousel {
outputs { outputs {
@@ -316,7 +318,7 @@ component Carousel {
view { view {
<section <section
{...attrs} {...attrs}
class="wire-next wire-next--carousel wire-next--color-{color} wire-next--size-{size} wire-next--variant-{variant} {class}" class="wire-component wire-next--carousel wire-component--color-{color} wire-component--size-{size} wire-next--variant-{variant} {class}"
data-rtl="{isRTL}" data-rtl="{isRTL}"
data-centered="{isCentered}" data-centered="{isCentered}"
data-draggable="{isDraggable && !isSnap}" data-draggable="{isDraggable && !isSnap}"
@@ -460,5 +462,371 @@ component Carousel {
</div> </div>
</div> </div>
</section> </section>
<ComponentBaseStyles hidden />
}
style {
.wire-next--carousel {
--wire-carousel-color: var(--wire-component-color, var(--wire-color-primary));
display: grid;
width: 100%;
min-width: 0;
gap: 1rem;
padding: 1rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-md);
color: var(--wire-color-text);
background: var(--wire-color-surface);
box-shadow: var(--wire-shadow-1);
}
.wire-next__carousel-header h3,
.wire-next__carousel-header p {
margin: 0;
}
.wire-next__carousel-header p {
margin-top: 0.35rem;
color: var(--wire-color-text-muted);
}
.wire-next__carousel-layout {
display: flex;
min-width: 0;
gap: 0.75rem;
}
.wire-next__carousel-main {
display: grid;
flex: 1;
min-width: 0;
gap: 0.75rem;
}
.wire-next__carousel-stage {
position: relative;
min-width: 0;
}
.wire-next__carousel-viewport {
position: relative;
overflow: hidden;
min-width: 0;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-md);
background: var(--wire-color-surface-subtle, var(--wire-color-surface));
outline: none;
}
.wire-next__carousel-viewport:focus-visible {
box-shadow: 0 0 0 3px color-mix(in srgb, var(--wire-carousel-color) 30%, transparent);
}
.wire-next__carousel-track {
display: flex;
align-items: stretch;
gap: var(--wire-carousel-gap);
transform: translateX(
calc(
var(--wire-carousel-index) * -1 *
(
(100% - (var(--wire-carousel-per-view) - 1) * var(--wire-carousel-gap)) /
var(--wire-carousel-per-view) + var(--wire-carousel-gap)
)
)
);
transition: transform var(--wire-motion-base) var(--wire-ease-emphasized);
translate: var(--wire-carousel-drag-offset, 0) 0;
will-change: transform;
}
.wire-next--carousel[data-dragging="true"] .wire-next__carousel-track {
transition: none;
}
.wire-next--carousel[data-rtl="true"] .wire-next__carousel-track {
transform: translateX(
calc(
var(--wire-carousel-index) *
(
(100% - (var(--wire-carousel-per-view) - 1) * var(--wire-carousel-gap)) /
var(--wire-carousel-per-view) + var(--wire-carousel-gap)
)
)
);
}
.wire-next__carousel-slide {
position: relative;
display: grid;
flex: 0 0
calc(
(100% - (var(--wire-carousel-per-view) - 1) * var(--wire-carousel-gap)) /
var(--wire-carousel-per-view)
);
overflow: hidden;
min-width: 0;
min-height: 20rem;
place-items: center;
background: var(--wire-color-surface-raised, var(--wire-color-surface));
}
.wire-next--carousel[data-auto-height="true"] .wire-next__carousel-slide {
min-height: 0;
}
.wire-next--carousel[data-centered="true"] .wire-next__carousel-slide {
flex-basis: min(78%, 32rem);
}
.wire-next--carousel[data-centered="true"] .wire-next__carousel-track {
box-sizing: border-box;
transform: translateX(
calc(var(--wire-carousel-index) * -1 * (min(78%, 32rem) + var(--wire-carousel-gap)))
);
}
.wire-next--carousel[data-centered="true"] .wire-next__carousel-slide:first-child {
margin-inline-start: calc((100% - min(78%, 32rem)) / 2);
}
.wire-next--carousel[data-centered="true"] .wire-next__carousel-slide:last-child {
margin-inline-end: calc((100% - min(78%, 32rem)) / 2);
}
.wire-next--carousel[data-centered="true"][data-rtl="true"] .wire-next__carousel-track {
transform: translateX(
calc(var(--wire-carousel-index) * (min(78%, 32rem) + var(--wire-carousel-gap)))
);
}
.wire-next__carousel-slide > img {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
inset: 0;
}
.wire-next__carousel-slide-content {
position: relative;
z-index: 1;
width: min(100%, 38rem);
padding: clamp(2rem, 8vw, 5rem);
text-align: center;
}
.wire-next__carousel-slide-content h4,
.wire-next__carousel-slide-content p {
margin: 0;
}
.wire-next__carousel-slide-content h4 {
font-size: clamp(1.5rem, 4vw, 2.4rem);
}
.wire-next__carousel-slide-content p {
margin-top: 0.65rem;
color: var(--wire-color-text-muted);
}
.wire-next__carousel-control {
position: absolute;
z-index: 3;
top: 50%;
display: grid;
width: 2.75rem;
min-height: 2.75rem;
padding: 0;
border: 1px solid color-mix(in srgb, var(--wire-color-border) 70%, transparent);
border-radius: 999px;
background: color-mix(in srgb, var(--wire-color-text) 76%, transparent);
color: var(--wire-color-surface);
cursor: pointer;
place-items: center;
transform: translateY(-50%);
}
.wire-next__carousel-control:focus-visible,
.wire-next__carousel-pagination button:focus-visible,
.wire-next__carousel-thumbnails button:focus-visible {
outline: 2px solid var(--wire-carousel-color);
outline-offset: 2px;
}
.wire-next__carousel-control:disabled {
cursor: not-allowed;
opacity: 0.35;
}
.wire-next__carousel-control--previous {
left: 1rem;
}
.wire-next__carousel-control--next {
right: 1rem;
}
.wire-next--carousel[data-rtl="true"] .wire-next__carousel-control--previous {
right: 1rem;
left: auto;
}
.wire-next--carousel[data-rtl="true"] .wire-next__carousel-control--next {
right: auto;
left: 1rem;
}
.wire-next__carousel-pagination {
display: flex;
min-height: 1.5rem;
align-items: center;
justify-content: center;
gap: 0.5rem;
}
.wire-next__carousel-pagination button {
width: 0.65rem;
min-height: 0.65rem;
padding: 0;
border: 1px solid var(--wire-color-text-muted);
border-radius: 999px;
background: transparent;
cursor: pointer;
}
.wire-next__carousel-pagination button[data-active="true"] {
border-color: var(--wire-carousel-color);
background: var(--wire-carousel-color);
}
.wire-next__carousel-counter {
position: absolute;
z-index: 3;
bottom: 0.8rem;
left: 50%;
padding: 0.25rem 0.65rem;
border-radius: 999px;
background: color-mix(in srgb, var(--wire-color-text) 82%, transparent);
color: var(--wire-color-surface);
font-weight: 700;
transform: translateX(-50%);
}
.wire-next__carousel-thumbnails {
display: flex;
overflow: auto;
gap: 0.55rem;
scrollbar-width: thin;
}
.wire-next__carousel-thumbnails button {
display: grid;
flex: 0 0 8.5rem;
min-height: 3.75rem;
overflow: hidden;
padding: 0;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-sm);
background: var(--wire-color-surface);
color: var(--wire-color-text);
cursor: pointer;
place-items: center;
}
.wire-next__carousel-thumbnails button[data-active="true"] {
border-color: var(--wire-carousel-color);
box-shadow: inset 0 0 0 1px var(--wire-carousel-color);
}
.wire-next__carousel-thumbnails img {
width: 100%;
height: 4rem;
object-fit: cover;
}
.wire-next__carousel-thumbnails span {
padding: 0.5rem;
}
.wire-next--carousel[data-thumbnails="vertical"] .wire-next__carousel-thumbnails {
flex: 0 0 9rem;
flex-direction: column;
max-height: 28rem;
}
.wire-next--carousel[data-thumbnails="vertical"] .wire-next__carousel-thumbnails button {
flex-basis: 7.5rem;
width: 100%;
}
.wire-next--carousel[data-draggable="true"] .wire-next__carousel-viewport {
cursor: grab;
touch-action: pan-y;
user-select: none;
-webkit-user-select: none;
}
.wire-next--carousel[data-draggable="true"] .wire-next__carousel-viewport:active {
cursor: grabbing;
}
.wire-next--carousel[data-draggable="true"] img,
.wire-next--carousel[data-draggable="true"] a {
-webkit-user-drag: none;
}
.wire-next--carousel[data-snap="true"] .wire-next__carousel-viewport {
overflow-x: auto;
scroll-behavior: smooth;
scroll-snap-type: x mandatory;
scrollbar-width: thin;
}
.wire-next--carousel[data-snap="true"] .wire-next__carousel-track {
--wire-carousel-snap-slide: calc(
(100% - (var(--wire-carousel-per-view) - 1) * var(--wire-carousel-gap)) /
var(--wire-carousel-per-view)
);
display: grid;
width: 100%;
min-width: 100%;
box-sizing: content-box;
grid-auto-columns: var(--wire-carousel-snap-slide);
grid-auto-flow: column;
padding-inline: calc((100% - var(--wire-carousel-snap-slide)) / 2);
transform: none;
}
.wire-next--carousel[data-snap="true"] .wire-next__carousel-slide {
width: auto;
min-width: 0;
scroll-snap-align: center;
}
@media (max-width: 640px) {
.wire-next__carousel-slide {
flex-basis: 100%;
min-height: 16rem;
}
.wire-next--carousel[data-thumbnails="vertical"] .wire-next__carousel-layout {
flex-direction: column-reverse;
}
.wire-next--carousel[data-thumbnails="vertical"] .wire-next__carousel-thumbnails {
flex: auto;
flex-direction: row;
max-height: none;
}
.wire-next--carousel[data-thumbnails="vertical"] .wire-next__carousel-thumbnails button {
flex-basis: 8.5rem;
width: auto;
}
}
@media (prefers-reduced-motion: reduce) {
.wire-next__carousel-track {
transition-duration: 0.01ms;
}
}
} }
} }
+93 -11
View File
@@ -1,25 +1,107 @@
component Chart { component Chart {
outputs { outputs {
select(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) select(payload: { item: object; index: number; sourceEvent?: Event })
dataPointClick(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]) dataPointClick(payload: { item: object; index: number; sourceEvent?: Event })
legendToggle(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]) legendToggle(payload: { item: object; index: number; hidden: boolean; sourceEvent?: Event })
} }
props { props {
size: string = "default"
color: string = "primary"
title: string = "Chart" title: string = "Chart"
description: string = "" description: string = ""
items: unknown[] = [] items: unknown[] = []
variant: string = "default" valueKey: string = "value"
labelKey: string = "label"
height: number = 240
showLegend: boolean = true
showValues: boolean = true
size: string = "default"
color: string = "primary"
variant: string = "bar"
class: string = "" class: string = ""
} }
state hiddenIndexes = []
functions {
shared function numericValue(item) { return Math.max(0, Number(item[valueKey]) || 0) }
shared function maximumValue() {
return Math.max(1, ...items.map(function (item) { return numericValue(item) }))
}
shared function isHidden(index) { return hiddenIndexes.includes(index) }
shared function barWidth() { return items.length ? Math.max(4, 80 / items.length) : 80 }
shared function barX(index) { return 10 + index * (80 / Math.max(1, items.length)) }
shared function barHeight(item) { return numericValue(item) / maximumValue() * 72 }
shared function barY(item) { return 84 - barHeight(item) }
client function selectPoint(item, index, sourceEvent) {
output.dataPointClick({ item: item, index: index, sourceEvent: sourceEvent })
output.select({ item: item, index: index, sourceEvent: sourceEvent })
}
client function toggleLegend(item, index, sourceEvent, next) {
next = hiddenIndexes.slice()
if (next.includes(index)) {
next = next.filter(function (value) { return value !== index })
} else {
next.push(index)
}
hiddenIndexes = next
output.legendToggle({ item: item, index: index, hidden: next.includes(index), sourceEvent: sourceEvent })
}
}
view { view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--chart wire-next--variant-{variant} {class}"> <figure {...attrs} data-ui-component="Chart" data-variant='{variant}' class='wire-chart {class}'>
{#if title}<strong>{title}</strong>{/if} {#if title || description}
{#if description}<p>{description}</p>{/if} <figcaption class="wire-chart__header">
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if} {#if title}<strong>{title}</strong>{/if}
{#if description}<span>{description}</span>{/if}
</figcaption>
{/if}
<svg class="wire-chart__plot" viewBox="0 0 100 100" role="img" aria-label='{title}' style='height:{height}px'>
<line x1="8" y1="84" x2="96" y2="84" class="wire-chart__axis" />
{#each items as item, index}
<g data-hidden='{isHidden(index) ? "true" : "false"}'>
<rect
x='{barX(index)}' y='{barY(item)}' width='{barWidth()}' height='{barHeight(item)}'
rx="1.5" class="wire-chart__bar" role="button" tabindex="0"
aria-label='{item[labelKey] + ": " + numericValue(item)}'
@click='selectPoint(item, index, event)'
@keydown='if (event.key === "Enter" || event.key === " ") { event.preventDefault(); selectPoint(item, index, event) }'
/>
{#if showValues}<text x='{barX(index) + barWidth() / 2}' y='{barY(item) - 3}' class="wire-chart__value">{numericValue(item)}</text>{/if}
<text x='{barX(index) + barWidth() / 2}' y="94" class="wire-chart__label">{item[labelKey]}</text>
</g>
{/each}
</svg>
{#if showLegend}
<div class="wire-chart__legend" aria-label="Chart legend">
{#each items as item, index}
<button type="button" aria-pressed='{isHidden(index) ? "false" : "true"}' @click='toggleLegend(item, index, event)'>
<span aria-hidden="true"></span>{item[labelKey]}
</button>
{/each}
</div>
{/if}
<slot /> <slot />
</section> </figure>
}
style {
.wire-chart { display: grid; gap: 1rem; min-width: 0; margin: 0; padding: 1rem; border: 1px solid var(--wire-color-border); border-radius: var(--wire-radius); color: var(--wire-color-text); background: var(--wire-color-surface); box-shadow: var(--wire-shadow-1); }
.wire-chart__header { display: grid; gap: 0.2rem; }
.wire-chart__header > span { color: var(--wire-color-muted); font-size: 0.8rem; }
.wire-chart__plot { display: block; width: 100%; min-height: 12rem; overflow: visible; }
.wire-chart__axis { stroke: var(--wire-color-border); stroke-width: 0.5; }
.wire-chart__bar { fill: var(--wire-color-primary); cursor: pointer; transition: opacity var(--wire-motion-fast), transform var(--wire-motion-fast); transform-box: fill-box; transform-origin: bottom; }
.wire-chart__bar:hover { opacity: 0.82; transform: scaleY(1.02); }
.wire-chart__bar:focus-visible { outline: 1.5px solid var(--wire-color-focus); outline-offset: 1px; }
.wire-chart__plot g[data-hidden="true"] { opacity: 0.18; pointer-events: none; }
.wire-chart__value, .wire-chart__label { fill: var(--wire-color-text); font-size: 3.5px; text-anchor: middle; }
.wire-chart__label { fill: var(--wire-color-muted); }
.wire-chart__legend { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.wire-chart__legend button { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.3rem 0.5rem; border: 1px solid var(--wire-color-border); border-radius: 999px; color: var(--wire-color-text); background: transparent; font: inherit; font-size: 0.75rem; cursor: pointer; }
.wire-chart__legend button > span { width: 0.65rem; height: 0.65rem; border-radius: 0.2rem; background: var(--wire-color-primary); }
.wire-chart__legend button[aria-pressed="false"] { opacity: 0.5; }
} }
} }
+203 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component ChatBubble { component ChatBubble {
outputs { outputs {
action(payload: { action: boolean; item: string | number | boolean | null | object; index: number }) action(payload: { action: boolean; item: string | number | boolean | null | object; index: number })
@@ -64,7 +66,7 @@ component ChatBubble {
view { view {
<section <section
{...attrs} {...attrs}
class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--chat-bubble wire-next--variant-{variant} {class}" class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--chat-bubble wire-next--variant-{variant} {class}"
data-one-sided="{oneSided}" data-one-sided="{oneSided}"
role="log" role="log"
aria-label="{ariaLabel}" aria-label="{ariaLabel}"
@@ -146,5 +148,205 @@ component ChatBubble {
{/if} {/if}
<slot /> <slot />
</section> </section>
<ComponentBaseStyles hidden />
}
style {
.wire-next--chat-bubble.wire-component--size-sm {
--wire-chat-padding: 0.75rem;
font-size: 0.875rem;
}
.wire-next--chat-bubble.wire-component--size-lg {
--wire-chat-padding: 1.25rem;
font-size: 1.0625rem;
}
.wire-next--chat-bubble {
--wire-chat-color: var(--wire-component-color, var(--wire-color-primary));
--wire-chat-padding: 1rem;
display: grid;
width: 100%;
min-width: 0;
gap: 1rem;
color: var(--wire-color-text);
}
.wire-next__chat-header h3,
.wire-next__chat-header p,
.wire-next__chat-content h4,
.wire-next__chat-content p {
margin: 0;
}
.wire-next__chat-header p {
margin-top: 0.35rem;
color: var(--wire-color-text-muted);
}
.wire-next__chat-thread {
display: grid;
min-width: 0;
gap: 1.25rem;
}
.wire-next__chat-message {
display: grid;
width: min(78%, 34rem);
min-width: 0;
justify-self: start;
gap: 0.4rem;
}
.wire-next__chat-message[data-direction="outgoing"] {
justify-self: end;
}
.wire-next--chat-bubble[data-one-sided="true"] .wire-next__chat-message {
justify-self: start;
}
.wire-next__chat-row {
display: flex;
min-width: 0;
align-items: flex-start;
gap: 0.75rem;
}
.wire-next__chat-message[data-direction="outgoing"] .wire-next__chat-row {
flex-direction: row-reverse;
}
.wire-next--chat-bubble[data-one-sided="true"]
.wire-next__chat-message[data-direction="outgoing"]
.wire-next__chat-row {
flex-direction: row;
}
.wire-next__chat-content {
min-width: 0;
padding: var(--wire-chat-padding);
border: 1px solid var(--wire-color-border);
border-radius: 1rem;
background: var(--wire-color-surface-raised, var(--wire-color-surface));
color: var(--wire-color-text);
cursor: pointer;
}
.wire-next__chat-content:focus-visible {
outline: 2px solid var(--wire-chat-color);
outline-offset: 2px;
}
.wire-next__chat-message[data-direction="outgoing"] .wire-next__chat-content {
border-color: var(--wire-chat-color);
background: var(--wire-chat-color);
color: var(--wire-color-primary-contrast, #fff);
}
.wire-next__chat-message[data-direction="outgoing"] .wire-next__chat-content :is(h4, p, li, span) {
color: inherit;
}
.wire-next__chat-content h4 {
margin-bottom: 0.65rem;
font-size: 1em;
}
.wire-next__chat-content p + p,
.wire-next__chat-content p + nav {
margin-top: 0.75rem;
}
.wire-next__chat-content ul {
display: grid;
margin: 0.55rem 0 0;
padding-inline-start: 1.25rem;
gap: 0.35rem;
}
.wire-next__chat-content nav {
display: grid;
margin-top: 0.75rem;
gap: 0.3rem;
}
.wire-next__chat-content a {
color: var(--wire-chat-color);
font-weight: 650;
text-decoration: none;
}
.wire-next__chat-message[data-direction="outgoing"] .wire-next__chat-content a {
color: inherit;
text-decoration: underline;
}
.wire-next__chat-avatar {
display: grid;
flex: 0 0 2.5rem;
width: 2.5rem;
min-height: 2.5rem;
overflow: hidden;
padding: 0;
border: 1px solid var(--wire-color-border);
border-radius: 999px;
background: var(--wire-color-surface-raised, var(--wire-color-surface));
color: var(--wire-color-text);
cursor: pointer;
place-items: center;
}
.wire-next__chat-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.wire-next__chat-avatar:focus-visible {
outline: 2px solid var(--wire-chat-color);
outline-offset: 2px;
}
.wire-next__chat-meta {
display: flex;
align-items: center;
gap: 0.3rem;
padding-inline: calc(2.5rem + 0.75rem);
color: var(--wire-color-text-muted);
font-size: 0.78em;
}
.wire-next__chat-message[data-direction="outgoing"] .wire-next__chat-meta {
justify-content: flex-end;
}
.wire-next__chat-meta[data-tone="danger"] {
color: var(--wire-color-danger);
}
.wire-next__chat-meta button {
padding: 0;
border: 0;
background: transparent;
color: inherit;
font: inherit;
font-weight: 700;
cursor: pointer;
text-decoration: underline;
}
@media (max-width: 640px) {
.wire-next__chat-message {
width: min(92%, 34rem);
}
.wire-next__chat-avatar {
flex-basis: 2rem;
width: 2rem;
min-height: 2rem;
}
.wire-next__chat-meta {
padding-inline: 0;
}
}
} }
} }
+83 -11
View File
@@ -1,25 +1,97 @@
component Clipboard { component Clipboard {
outputs { outputs {
copy(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]) copy(payload: { value: string; sourceEvent?: Event })
success(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) success(payload: { value: string; sourceEvent?: Event })
error(payload: { error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string) error(payload: { error: Error | string; value: string; sourceEvent?: Event })
} }
props { props {
size: string = "default" value: string = ""
color: string = "primary" label: string = "Copy"
copiedLabel: string = "Copied"
errorLabel: string = "Copy failed"
title: string = "Clipboard" title: string = "Clipboard"
description: string = "" description: string = ""
items: unknown[] = [] code: boolean = true
variant: string = "default" size: string = "default"
color: string = "primary"
disabled: boolean = false
class: string = "" class: string = ""
} }
state status = "idle"
functions {
client function resetStatus() { status = "idle" }
client function copySucceeded() {
status = "success"
output.success({ value: value })
setTimeout(resetStatus, 1600)
}
client function copyFailed(error) {
status = "error"
output.error({ error: error, value: value })
setTimeout(resetStatus, 1600)
}
client function copyValue(sourceEvent) {
if (disabled || status === "copying") {
return
}
status = "copying"
output.copy({ value: value, sourceEvent: sourceEvent })
if (!window.navigator.clipboard || !window.navigator.clipboard.writeText) {
copyFailed(new Error("Clipboard API is unavailable"))
return
}
return window.navigator.clipboard.writeText(value).then(copySucceeded).catch(copyFailed)
}
}
view { view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--clipboard wire-next--variant-{variant} {class}"> <section
{#if title}<strong>{title}</strong>{/if} {...attrs}
{#if description}<p>{description}</p>{/if} data-ui-component="Clipboard"
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if} data-status='{status}'
data-size='{size}'
data-color='{color}'
class='wire-clipboard {class}'
>
{#if title}<strong class="wire-clipboard__title">{title}</strong>{/if}
{#if description}<p class="wire-clipboard__description">{description}</p>{/if}
<div class="wire-clipboard__control">
{#if code}
<code class="wire-clipboard__value">{value}</code>
{:else}
<span class="wire-clipboard__value">{value}</span>
{/if}
<button
type="button"
class="wire-clipboard__button"
disabled='{disabled}'
aria-label='{status === "success" ? copiedLabel : status === "error" ? errorLabel : label}'
@click='copyValue(event)'
>
<span class="icon-[lucide--copy] wire-clipboard__icon" data-show='status !== "success"' aria-hidden="true"></span>
<span class="icon-[lucide--check] wire-clipboard__icon" data-show='status === "success"' aria-hidden="true"></span>
<span>{status === "success" ? copiedLabel : status === "error" ? errorLabel : label}</span>
</button>
</div>
<slot /> <slot />
</section> </section>
} }
style {
.wire-clipboard { display: grid; gap: 0.5rem; color: var(--wire-color-text); }
.wire-clipboard__title { font-size: 0.875rem; }
.wire-clipboard__description { margin: 0; color: var(--wire-color-muted); font-size: 0.8rem; }
.wire-clipboard__control { display: flex; min-width: 0; align-items: stretch; overflow: hidden; border: 1px solid var(--wire-color-border); border-radius: var(--wire-radius); background: var(--wire-color-surface); box-shadow: var(--wire-shadow-1); }
.wire-clipboard__value { min-width: 0; flex: 1; overflow: auto; padding: 0.7rem 0.85rem; color: var(--wire-color-text); background: var(--wire-color-surface-2); font: inherit; font-family: var(--wire-font-mono, ui-monospace, monospace); white-space: nowrap; }
.wire-clipboard__button { display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.6rem 0.85rem; border: 0; border-left: 1px solid var(--wire-color-border); color: var(--wire-color-primary); background: transparent; font: inherit; font-size: 0.8rem; font-weight: 700; cursor: pointer; }
.wire-clipboard__button:hover { background: var(--wire-color-primary-soft); }
.wire-clipboard__button:focus-visible { outline: 2px solid var(--wire-color-focus); outline-offset: -3px; }
.wire-clipboard__button:disabled { cursor: not-allowed; opacity: 0.55; }
.wire-clipboard[data-status="success"] .wire-clipboard__button { color: var(--wire-color-success); }
.wire-clipboard[data-status="error"] .wire-clipboard__button { color: var(--wire-color-danger); }
.wire-clipboard__icon { width: 1rem; height: 1rem; flex: none; }
}
} }
+152 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Collapse { component Collapse {
outputs { outputs {
toggle(payload: { index: number; item: string | number | boolean | null | object; open: boolean; openIndexes: number[] }) toggle(payload: { index: number; item: string | number | boolean | null | object; open: boolean; openIndexes: number[] })
@@ -51,7 +53,7 @@ size: string = "default"
view { view {
<section <section
{...attrs} {...attrs}
class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--collapse {class}" class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--collapse {class}"
data-mode="{mode}" data-mode="{mode}"
aria-label="{ariaLabel}" aria-label="{ariaLabel}"
> >
@@ -94,5 +96,154 @@ size: string = "default"
{/each} {/each}
<slot /> <slot />
</section> </section>
<ComponentBaseStyles hidden />
}
style {
.wire-next--collapse.wire-component--size-sm {
font-size: 0.875rem;
}
.wire-next--collapse.wire-component--size-lg {
font-size: 1.0625rem;
}
.wire-next--collapse {
--wire-collapse-color: var(--wire-component-color, var(--wire-color-primary));
display: grid;
width: 100%;
min-width: 0;
gap: 0.75rem;
color: var(--wire-color-text);
}
.wire-next__collapse-item {
display: grid;
min-width: 0;
justify-items: start;
gap: 0;
}
.wire-next__collapse-trigger {
display: inline-flex;
min-height: 2.75rem;
align-items: center;
justify-content: center;
gap: 0.55rem;
padding: 0.7rem 1rem;
border: 1px solid var(--wire-collapse-color);
border-radius: var(--wire-radius-sm);
background: var(--wire-collapse-color);
color: var(--wire-color-primary-contrast, #fff);
font: inherit;
font-weight: 700;
cursor: pointer;
}
.wire-next__collapse-trigger:focus-visible {
outline: 2px solid var(--wire-collapse-color);
outline-offset: 3px;
}
.wire-next__collapse-trigger:disabled {
cursor: not-allowed;
opacity: 0.5;
}
.wire-next__collapse-chevron {
transition: transform var(--wire-motion-fast) var(--wire-ease-standard);
}
.wire-next__collapse-item[data-open="true"] .wire-next__collapse-chevron {
transform: rotate(180deg);
}
.wire-next__collapse-panel {
width: min(100%, 42rem);
max-height: 0;
overflow: hidden;
margin-top: 0;
opacity: 0;
transition:
max-height 350ms var(--wire-ease-emphasized),
margin-top 300ms var(--wire-ease-emphasized),
opacity 200ms var(--wire-ease-standard);
}
.wire-next__collapse-panel[data-open="true"] {
max-height: 40rem;
margin-top: 0.75rem;
opacity: 1;
}
.wire-next__collapse-content {
display: grid;
overflow: hidden;
min-height: 0;
gap: 0.65rem;
padding: 1rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-md);
background: var(--wire-color-surface-raised, var(--wire-color-surface));
}
.wire-next__collapse-content h4,
.wire-next__collapse-content p,
.wire-next__collapse-preview {
margin: 0;
}
.wire-next__collapse-content nav {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
}
.wire-next__collapse-content a {
color: var(--wire-collapse-color);
font-weight: 650;
text-decoration: none;
}
.wire-next--collapse[data-mode="inline"] .wire-next__collapse-item {
gap: 0;
}
.wire-next--collapse[data-mode="inline"] .wire-next__collapse-preview {
order: 1;
margin-bottom: 0.5rem;
}
.wire-next--collapse[data-mode="inline"] .wire-next__collapse-panel {
order: 2;
width: 100%;
}
.wire-next--collapse[data-mode="inline"] .wire-next__collapse-panel[data-open="true"] {
margin-top: 0;
}
.wire-next--collapse[data-mode="inline"] .wire-next__collapse-trigger {
order: 3;
margin-top: 0.5rem;
min-height: auto;
padding: 0;
border: 0;
border-radius: 0;
background: transparent;
color: var(--wire-collapse-color);
}
.wire-next--collapse[data-mode="inline"] .wire-next__collapse-content {
padding: 0;
border: 0;
background: transparent;
}
@media (prefers-reduced-motion: reduce) {
.wire-next__collapse-chevron,
.wire-next__collapse-panel {
transition: none;
}
}
} }
} }
+14 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component ColorPicker { component ColorPicker {
outputs { outputs {
input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -32,10 +36,19 @@ component ColorPicker {
client function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } client function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() }
} }
view { view {
<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 {...attrs} class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--field wire-component--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__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> <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> {#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div> </div>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next__color-control input[type="color"] {
width: 3rem;
padding: 0.2rem;
}
} }
} }
+32 -1
View File
@@ -1,3 +1,7 @@
import SelectStyles from "../styles/SelectStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component ComboBox { component ComboBox {
outputs { outputs {
search(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) search(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -225,7 +229,7 @@ component ComboBox {
view { view {
<div <div
class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--advanced-select wire-next--combobox {open ? 'wire-next--open' : ''} {fixed ? 'wire-next--advanced-select-fixed' : ''} {invalid ? 'wire-next--invalid' : ''} {disabled ? 'wire-next--disabled' : ''} {class}" class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--advanced-select wire-next--combobox {open ? 'wire-next--open' : ''} {fixed ? 'wire-next--advanced-select-fixed' : ''} {invalid ? 'wire-next--invalid' : ''} {disabled ? 'wire-next--disabled' : ''} {class}"
data-placement="{placement}" data-placement="{placement}"
data-search-mode="{searchMode}" data-search-mode="{searchMode}"
data-remote="{remote ? 'true' : 'false'}" data-remote="{remote ? 'true' : 'false'}"
@@ -385,5 +389,32 @@ component ComboBox {
data-error="{name}" data-error="{name}"
>{validationMessage}</small> >{validationMessage}</small>
</div> </div>
<SelectStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next__combobox-toggle {
position: absolute;
top: 50%;
right: 0;
z-index: 1;
display: grid;
width: 2.25em;
height: 100%;
padding: 0;
place-items: center;
border: 0;
color: var(--wire-color-muted);
background: transparent;
cursor: pointer;
transform: translateY(-50%);
}
.wire-next--combobox .wire-next__combobox-input {
padding-right: 5.25em;
padding-left: 2.5em;
cursor: text;
}
} }
} }
+59 -11
View File
@@ -1,24 +1,72 @@
component Confetti { component Confetti {
outputs { outputs {
start(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) start(payload: { sourceEvent?: Event; duration: number })
complete(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) complete(payload: { sourceEvent?: Event; duration: number })
} }
props { props {
label: string = "Celebrate"
duration: number = 1200
count: number = 24
autoStart: boolean = false
disabled: boolean = false
size: string = "default" size: string = "default"
color: string = "primary" color: string = "primary"
title: string = "Confetti"
description: string = ""
items: unknown[] = []
variant: string = "default"
class: string = "" class: string = ""
} }
state running = false
functions {
shared function pieces() { return Array.from({ length: Math.max(1, Math.min(60, count)) }) }
shared function pieceStyle(index) {
return "--wire-confetti-index:" + index + ";--wire-confetti-x:" + ((index * 37) % 100) + ";--wire-confetti-delay:" + ((index * 29) % 240) + "ms;"
}
client function finish(sourceEvent) {
running = false
output.complete({ sourceEvent: sourceEvent, duration: duration })
}
client function start(sourceEvent) {
if (disabled || running) {
return
}
running = true
output.start({ sourceEvent: sourceEvent, duration: duration })
setTimeout(finish, duration, sourceEvent)
}
}
lifecycle {
mount { if (autoStart) { start(null) } }
}
view { view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--confetti wire-next--variant-{variant} {class}"> <div {...attrs} data-ui-component="Confetti" data-running='{running ? "true" : "false"}' class='wire-confetti {class}' style='--wire-confetti-duration:{duration}ms'>
{#if title}<strong>{title}</strong>{/if} <button type="button" class="wire-confetti__trigger" disabled='{disabled}' @click='start(event)'>
{#if description}<p>{description}</p>{/if} <span class="icon-[lucide--party-popper]" aria-hidden="true"></span><span>{label}</span>
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if} </button>
<div class="wire-confetti__burst" aria-hidden="true">
{#each pieces() as piece, index}<i style='{pieceStyle(index)}'></i>{/each}
</div>
<slot /> <slot />
</section> </div>
}
style {
.wire-confetti { position: relative; display: inline-flex; }
.wire-confetti__trigger { display: inline-flex; min-height: 2.5rem; align-items: center; gap: 0.5rem; padding: 0.55rem 0.85rem; border: 1px solid var(--wire-color-primary); border-radius: var(--wire-radius); color: var(--wire-color-on-primary); background: var(--wire-color-primary); font: inherit; font-weight: 700; cursor: pointer; }
.wire-confetti__trigger > span:first-child { width: 1rem; height: 1rem; }
.wire-confetti__trigger:focus-visible { outline: 2px solid var(--wire-color-focus); outline-offset: 2px; }
.wire-confetti__trigger:disabled { cursor: not-allowed; opacity: 0.55; }
.wire-confetti__burst { position: absolute; inset: 50% 0 auto; height: 0; pointer-events: none; }
.wire-confetti__burst > i { position: absolute; left: calc(var(--wire-confetti-x) * 1%); width: 0.45rem; height: 0.7rem; border-radius: 0.1rem; opacity: 0; background: hsl(calc(var(--wire-confetti-index) * 47deg) 80% 55%); transform: translate(-50%, 0) rotate(calc(var(--wire-confetti-index) * 23deg)); }
.wire-confetti[data-running="true"] .wire-confetti__burst > i { animation: wire-confetti-burst var(--wire-confetti-duration) cubic-bezier(0.2, 0.7, 0.2, 1) var(--wire-confetti-delay) both; }
@keyframes wire-confetti-burst {
0% { opacity: 1; transform: translate(-50%, 0) rotate(0); }
100% { opacity: 0; transform: translate(calc(-50% + (var(--wire-confetti-x) - 50) * 0.9px), 9rem) rotate(540deg); }
}
@media (prefers-reduced-motion: reduce) {
.wire-confetti[data-running="true"] .wire-confetti__burst > i { animation-duration: 1ms; animation-delay: 0ms; }
}
} }
} }
-26
View File
@@ -1,26 +0,0 @@
component CopyMarkup {
outputs {
copy(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])
success(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
error(payload: { error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string)
}
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 = ""
}
view {
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--copy-markup {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>
}
}
+19 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component DataMap { component DataMap {
outputs { outputs {
select(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) select(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -14,11 +16,27 @@ component DataMap {
class: string = "" class: string = ""
} }
view { view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--data-map wire-next--variant-{variant} {class}"> <section class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--data-map wire-next--variant-{variant} {class}">
{#if title}<strong>{title}</strong>{/if} {#if title}<strong>{title}</strong>{/if}
{#if description}<p>{description}</p>{/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} {#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
<slot /> <slot />
</section> </section>
<ComponentBaseStyles hidden />
}
style {
.wire-next--data-map {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius);
color: var(--wire-color-text);
background: var(--wire-color-surface);
}
.wire-next--data-map > p { margin: 0; color: var(--wire-color-muted); }
.wire-next--data-map > .wire-next__items { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.wire-next--data-map > .wire-next__items > span { padding: 0.35rem 0.6rem; border-radius: var(--wire-radius-sm); background: var(--wire-color-surface-2); }
} }
} }
+20 -7
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
// //
// DataTable -- columns, sorting, filtering, pagination and selection over an // DataTable -- columns, sorting, filtering, pagination and selection over an
// array of records. // array of records.
@@ -121,7 +123,7 @@ component DataTable {
state query = "" state query = ""
state sortKey = "" state sortKey = ""
state sortDirection = "asc" state sortDirection = "asc"
state page = 1 state paginationPage = 1
state perPage = pageSize state perPage = pageSize
state selectedKeys = [] state selectedKeys = []
state remoteRows = [] state remoteRows = []
@@ -273,7 +275,7 @@ component DataTable {
// page number past the end, and a table showing nothing with rows // page number past the end, and a table showing nothing with rows
// available is worse than one that quietly lands on the last page. // available is worse than one that quietly lands on the last page.
shared function currentPage() { shared function currentPage() {
return Math.min(Math.max(1, Number(page) || 1), pageCount()) return Math.min(Math.max(1, Number(paginationPage) || 1), pageCount())
} }
shared function visibleRows() { shared function visibleRows() {
@@ -576,7 +578,7 @@ component DataTable {
sortKey = key sortKey = key
sortDirection = "asc" sortDirection = "asc"
} }
page = 1 paginationPage = 1
output.sort({ key: sortKey, direction: sortDirection }) output.sort({ key: sortKey, direction: sortDirection })
reload() reload()
output.change(viewState()) output.change(viewState())
@@ -584,7 +586,7 @@ component DataTable {
client function updateQuery(sourceEvent) { client function updateQuery(sourceEvent) {
query = sourceEvent.target.value query = sourceEvent.target.value
page = 1 paginationPage = 1
output.search({ query: query }) output.search({ query: query })
reload() reload()
output.change(viewState()) output.change(viewState())
@@ -592,7 +594,7 @@ component DataTable {
client function goToPage(next) { client function goToPage(next) {
var target = Math.min(Math.max(1, next), pageCount()) var target = Math.min(Math.max(1, next), pageCount())
page = target paginationPage = target
output.pageChange({ page: target, pageSize: Number(perPage) || 10 }) output.pageChange({ page: target, pageSize: Number(perPage) || 10 })
reload() reload()
output.change(viewState()) output.change(viewState())
@@ -602,7 +604,7 @@ component DataTable {
// takes the Dropdown select detail directly. // takes the Dropdown select detail directly.
client function pickPageSize(detail) { client function pickPageSize(detail) {
perPage = Number(detail && detail.value) || 10 perPage = Number(detail && detail.value) || 10
page = 1 paginationPage = 1
output.pageChange({ page: 1, pageSize: perPage }) output.pageChange({ page: 1, pageSize: perPage })
reload() reload()
output.change(viewState()) output.change(viewState())
@@ -613,7 +615,7 @@ component DataTable {
// clicks. // clicks.
client function clearSearch() { client function clearSearch() {
query = "" query = ""
page = 1 paginationPage = 1
output.search({ query: "" }) output.search({ query: "" })
reload() reload()
} }
@@ -1043,9 +1045,20 @@ component DataTable {
<slot></slot> <slot></slot>
</div> </div>
<ComponentBaseStyles hidden />
} }
style { style {
.wire-next--data-map {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-md);
background: var(--wire-color-surface);
box-shadow: var(--wire-shadow-1);
}
.wire-table { .wire-table {
--table-accent: var(--wire-color-primary); --table-accent: var(--wire-color-primary);
display: flex; display: flex;
+64 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component DatePicker { component DatePicker {
outputs { outputs {
input(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]) input(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])
@@ -52,11 +56,70 @@ size: string = "default"
client function handleInvalid(sourceEvent) { output.invalid({ name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } client function handleInvalid(sourceEvent) { output.invalid({ name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) }
} }
view { view {
<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 {...attrs} class="wire-component wire-component--color-{color} wire-component--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__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__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> <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> {#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div> </div>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next__picker-clear {
position: absolute;
right: 2.5rem;
border: 0;
background: transparent;
color: var(--wire-color-muted);
}
.wire-next__date-selectors {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
gap: 0.65rem;
}
.wire-next__date-selectors label {
display: grid;
gap: 0.3rem;
color: var(--wire-color-muted);
font-size: 0.78rem;
font-weight: 600;
}
.wire-next__date-selectors select {
width: 100%;
min-height: 2.35rem;
padding: 0.45rem 0.65rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-sm);
background: var(--wire-color-surface);
color: var(--wire-color-text);
font: inherit;
}
.wire-next__date-done {
background: var(--wire-field-color) !important;
color: var(--wire-color-primary-contrast, #fff) !important;
font-weight: 650;
}
.wire-next__calendar > header {
display: grid;
grid-template-columns: 2.25rem 1fr 2.25rem;
align-items: center;
text-align: center;
}
.wire-next__calendar-grid button[data-outside="true"] {
color: var(--wire-color-muted);
opacity: 0.55;
}
.wire-next__calendar-grid button[data-today="true"] {
box-shadow: inset 0 0 0 1px var(--wire-field-color);
}
} }
} }
+77 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component DeviceFrame { component DeviceFrame {
outputs { outputs {
change(payload: { device: string; orientation: string; sourceEvent: Event }) change(payload: { device: string; orientation: string; sourceEvent: Event })
@@ -26,9 +28,83 @@ component DeviceFrame {
client function rotateFrame(sourceEvent) { currentOrientation = currentOrientation === "portrait" ? "landscape" : "portrait"; output.rotate({ device: device, orientation: currentOrientation, sourceEvent: sourceEvent }); output.change({ device: device, orientation: currentOrientation, sourceEvent: sourceEvent }) } client function rotateFrame(sourceEvent) { currentOrientation = currentOrientation === "portrait" ? "landscape" : "portrait"; output.rotate({ device: device, orientation: currentOrientation, sourceEvent: sourceEvent }); output.change({ device: device, orientation: currentOrientation, sourceEvent: sourceEvent }) }
} }
view { view {
<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}"> <section {...attrs} class="wire-component wire-component--color-{color} wire-component--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> <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> <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> </section>
<ComponentBaseStyles hidden />
}
style {
.wire-next--device-frame {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-md);
background: var(--wire-color-surface);
box-shadow: var(--wire-shadow-1);
}
.wire-next--device-frame > header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
.wire-next__device-actions {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
}
.wire-next__device-actions button {
min-height: 2.25rem;
padding-inline: 0.7rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-sm);
background: var(--wire-color-surface-2);
color: inherit;
}
.wire-next__device-shell {
overflow: hidden;
width: min(100%, 24rem);
min-height: 28rem;
margin-inline: auto;
border: 0.65rem solid var(--wire-color-text);
border-radius: 2rem;
background: var(--wire-color-background);
transition: width var(--wire-motion-normal) var(--wire-ease-standard);
}
.wire-next--device-frame[data-device="tablet"] .wire-next__device-shell {
width: min(100%, 42rem);
}
.wire-next--device-frame[data-device="desktop"] .wire-next__device-shell {
width: 100%;
border-width: 0.4rem;
border-radius: var(--wire-radius-md);
}
.wire-next--device-frame[data-orientation="landscape"] .wire-next__device-shell {
width: min(100%, 48rem);
min-height: 20rem;
}
.wire-next__device-shell :is(iframe, .wire-next__device-content) {
width: 100%;
min-height: inherit;
border: 0;
}
@media (max-width: 640px) {
.wire-next--device-frame > header {
align-items: stretch;
flex-direction: column;
}
}
} }
} }
+19 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component DragAndDrop { component DragAndDrop {
outputs { outputs {
dragStart(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) dragStart(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
@@ -18,11 +20,27 @@ component DragAndDrop {
class: string = "" class: string = ""
} }
view { view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--drag-and-drop wire-next--variant-{variant} {class}"> <section class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--drag-and-drop wire-next--variant-{variant} {class}">
{#if title}<strong>{title}</strong>{/if} {#if title}<strong>{title}</strong>{/if}
{#if description}<p>{description}</p>{/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} {#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
<slot /> <slot />
</section> </section>
<ComponentBaseStyles hidden />
}
style {
.wire-next--drag-and-drop {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius);
color: var(--wire-color-text);
background: var(--wire-color-surface);
}
.wire-next--drag-and-drop > p { margin: 0; color: var(--wire-color-muted); }
.wire-next--drag-and-drop > .wire-next__items { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.wire-next--drag-and-drop > .wire-next__items > span { padding: 0.35rem 0.6rem; border-radius: var(--wire-radius-sm); background: var(--wire-color-surface-2); }
} }
} }
+25 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component FileInput { component FileInput {
outputs { outputs {
input(payload: { files: File[]; name: string; sourceEvent: Event }) input(payload: { files: File[]; name: string; sourceEvent: Event })
@@ -46,10 +50,30 @@ size: string = "default"
client function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } client function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() }
} }
view { view {
<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 {...attrs} class="wire-component wire-component--color-{color} wire-component--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__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> <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> {#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div> </div>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next__file-control {
position: relative;
min-height: 2.75rem;
padding: 0.65rem 0.85rem;
border: 1px dashed var(--wire-color-border);
border-radius: var(--wire-radius-sm);
background: var(--wire-color-surface);
}
.wire-next__file-control input {
position: absolute;
cursor: pointer;
opacity: 0;
inset: 0;
}
} }
} }
-29
View File
@@ -1,29 +0,0 @@
component FileUpload {
outputs {
select(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
upload(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
progress(payload: { progress: number; [key: string]: string | number | boolean | null | object } | number)
success(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
error(payload: { error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string)
cancel(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
remove(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
}
props {
size: string = "default"
color: string = "primary"
title: string = "File Upload"
description: string = ""
items: unknown[] = []
variant: string = "default"
class: string = ""
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--file-upload 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>
}
}
+54 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component FileUploadProgress { component FileUploadProgress {
outputs { outputs {
cancel(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]) cancel(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])
@@ -30,11 +34,60 @@ size: string = "default"
client function completeUpload(sourceEvent) { currentValue = max; currentStatus = "complete"; output.complete(detail(sourceEvent)) } client function completeUpload(sourceEvent) { currentValue = max; currentStatus = "complete"; output.complete(detail(sourceEvent)) }
} }
view { view {
<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 {...attrs} class="wire-component wire-component--color-{color} wire-component--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> <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> <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-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 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> </div>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next__row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
.wire-next--file-upload-progress progress {
width: 100%;
accent-color: var(--wire-color-primary);
}
.wire-next--file-upload-progress {
display: grid;
width: min(100%, 36rem);
gap: 0.75rem;
padding: 1rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-md);
background: var(--wire-color-surface);
box-shadow: var(--wire-shadow-1);
}
.wire-next--file-upload-progress progress {
width: 100%;
height: 0.55rem;
overflow: hidden;
border: 0;
border-radius: 999px;
accent-color: var(--wire-component-color);
}
.wire-next__upload-actions {
justify-content: flex-end;
}
.wire-next__upload-actions button {
min-height: 2.25rem;
padding-inline: 0.8rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-sm);
background: var(--wire-color-surface-2);
color: inherit;
}
} }
} }
+39 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component InputGroup { component InputGroup {
outputs { outputs {
input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -39,7 +43,7 @@ component InputGroup {
client function handleAction(sourceEvent) { output.action({ name: name, sourceEvent: sourceEvent }) } client function handleAction(sourceEvent) { output.action({ name: name, sourceEvent: sourceEvent }) }
} }
view { view {
<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 {...attrs} class="wire-component wire-component--color-{color} wire-component--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__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"> <div class="wire-next__input-group-control">
{#if startText}<span class="wire-next__input-addon">{startText}</span>{/if} {#if startText}<span class="wire-next__input-addon">{startText}</span>{/if}
@@ -50,5 +54,39 @@ component InputGroup {
</div> </div>
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small> {#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div> </div>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next__input-group-control {
overflow: hidden;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-sm);
background: var(--wire-color-surface);
}
.wire-next__input-group-control input {
flex: 1;
min-width: 0;
border: 0;
box-shadow: none;
}
.wire-next__input-addon,
.wire-next__input-group-control button {
padding: 0.7rem 0.85rem;
white-space: nowrap;
}
.wire-next__input-group-control button {
align-self: stretch;
border: 0;
background: var(--wire-field-color);
color: var(--wire-color-primary-contrast, #fff);
font: inherit;
font-weight: 700;
cursor: pointer;
}
} }
} }
+82 -26
View File
@@ -418,19 +418,20 @@ component InputNumber {
data-value='{currentValue}' data-value='{currentValue}'
data-invalid='{isInvalid() ? "true" : "false"}' data-invalid='{isInvalid() ? "true" : "false"}'
data-disabled='{disabled ? "true" : "false"}' data-disabled='{disabled ? "true" : "false"}'
data-full-width='{fullWidth ? "true" : "false"}'
style='--input-number-accent: {componentColor()};' style='--input-number-accent: {componentColor()};'
class='relative flex flex-col gap-1.5 text-[var(--wire-color-text)] {fullWidth ? "w-full" : variant === "compact" ? "w-fit max-w-full" : "w-full max-w-sm"} {disabled ? "opacity-60" : ""} {class}' class='wire-input-number {class}'
> >
{#if label !== "" && variant !== "labeled" && variant !== "seat"} {#if label !== "" && variant !== "labeled" && variant !== "seat"}
<label <label
for='{inputId()}' for='{inputId()}'
class='inline-flex items-center gap-1 text-sm font-semibold leading-5 text-[var(--wire-color-text)]' class='wire-input-number__label'
> >
<span>{label}</span> <span>{label}</span>
{#if required} {#if required}
<span <span
aria-hidden="true" aria-hidden="true"
class='text-[var(--wire-color-danger)]' class='wire-input-number__required'
>*</span> >*</span>
{/if} {/if}
</label> </label>
@@ -439,14 +440,14 @@ component InputNumber {
{#if description !== "" && variant !== "labeled" && variant !== "seat"} {#if description !== "" && variant !== "labeled" && variant !== "seat"}
<p <p
id='{descriptionId()}' id='{descriptionId()}'
class='m-0 text-xs leading-5 text-[var(--wire-color-muted)]' class='wire-input-number__description'
> >
{description} {description}
</p> </p>
{/if} {/if}
<div <div
class='group flex min-w-0 overflow-hidden border bg-[var(--wire-color-surface)] text-[var(--wire-color-text)] shadow-[var(--wire-shadow-1)] transition-[border-color,box-shadow,background-color] duration-[var(--wire-motion-base)] ease-[var(--wire-ease-standard)] focus-within:border-[var(--input-number-accent)] focus-within:shadow-[0_0_0_3px_color-mix(in_srgb,var(--input-number-accent)_18%,transparent)] {variant === "compact" ? "rounded-full" : "rounded-[var(--wire-radius-sm)]"} {size === "xs" ? "min-h-8 text-xs" : size === "sm" ? "min-h-9 text-sm" : size === "lg" ? "min-h-12 text-base" : size === "xl" ? "min-h-14 text-lg" : "min-h-10 text-sm"} {isInvalid() ? "border-[var(--wire-color-danger)] focus-within:border-[var(--wire-color-danger)] focus-within:shadow-[0_0_0_3px_color-mix(in_srgb,var(--wire-color-danger)_18%,transparent)]" : "border-[var(--wire-color-border)]"} {disabled ? "cursor-not-allowed bg-[var(--wire-color-surface-2)]" : ""}' class='wire-input-number__control'
> >
{#if variant === "horizontal" && showButtons} {#if variant === "horizontal" && showButtons}
<button <button
@@ -455,30 +456,30 @@ component InputNumber {
aria-controls='{inputId()}' aria-controls='{inputId()}'
disabled='{decrementDisabled()}' disabled='{decrementDisabled()}'
@click='decrementValue(event)' @click='decrementValue(event)'
class='inline-flex shrink-0 items-center justify-center border-r border-[var(--wire-color-border)] bg-transparent text-[var(--wire-color-muted)] transition-[color,background-color] duration-[var(--wire-motion-fast)] hover:bg-[var(--wire-color-surface-2)] hover:text-[var(--input-number-accent)] focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--input-number-accent)] disabled:cursor-not-allowed disabled:opacity-40 {size === "xs" ? "w-8" : size === "sm" ? "w-9" : size === "lg" ? "w-12" : size === "xl" ? "w-14" : "w-10"}' class='wire-input-number__button wire-input-number__button--start'
> >
<span <span
aria-hidden="true" aria-hidden="true"
class='icon-[lucide--minus] size-4' class='icon-[lucide--minus] wire-input-number__icon'
></span> ></span>
</button> </button>
{/if} {/if}
<div <div
class='flex min-w-0 flex-1 {variant === "labeled" ? "flex-col items-stretch justify-center gap-0.5" : variant === "seat" ? "items-center justify-between gap-3" : "items-center"} {size === "xs" ? "px-2" : size === "sm" ? "px-2.5" : size === "lg" ? "px-4" : size === "xl" ? "px-5" : "px-3"}' class='wire-input-number__content'
> >
{#if variant === "labeled" || variant === "seat"} {#if variant === "labeled" || variant === "seat"}
<div class='min-w-0 flex-1'> <div class='wire-input-number__copy'>
{#if label !== ""} {#if label !== ""}
<label <label
for='{inputId()}' for='{inputId()}'
class='block truncate font-semibold leading-4 text-[var(--wire-color-text)] {variant === "labeled" ? "text-xs font-medium text-[var(--wire-color-muted)]" : "text-sm"}' class='wire-input-number__inner-label'
> >
{label} {label}
{#if required} {#if required}
<span <span
aria-hidden="true" aria-hidden="true"
class='ml-0.5 text-[var(--wire-color-danger)]' class='wire-input-number__required'
>*</span> >*</span>
{/if} {/if}
</label> </label>
@@ -487,7 +488,7 @@ component InputNumber {
{#if description !== ""} {#if description !== ""}
<span <span
id='{descriptionId()}' id='{descriptionId()}'
class='block truncate text-xs leading-4 text-[var(--wire-color-muted)]' class='wire-input-number__inner-description'
> >
{description} {description}
</span> </span>
@@ -496,12 +497,12 @@ component InputNumber {
{/if} {/if}
<div <div
class='flex min-w-0 items-center {variant === "seat" ? "w-auto shrink-0" : "w-full"}' class='wire-input-number__field'
> >
{#if prefix !== ""} {#if prefix !== ""}
<span <span
aria-hidden="true" aria-hidden="true"
class='shrink-0 pr-1.5 text-[var(--wire-color-muted)]' class='wire-input-number__prefix'
> >
{prefix} {prefix}
</span> </span>
@@ -531,13 +532,13 @@ component InputNumber {
@change='handleChange(event)' @change='handleChange(event)'
@keydown='handleKeydown(event)' @keydown='handleKeydown(event)'
@wheel='handleWheel(event)' @wheel='handleWheel(event)'
class='min-w-0 flex-1 appearance-none border-0 bg-transparent p-0 font-medium leading-none text-[var(--wire-color-text)] outline-none placeholder:text-[var(--wire-color-muted)] read-only:cursor-default disabled:cursor-not-allowed [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none {variant === "horizontal" || variant === "compact" || variant === "seat" ? "text-center" : "text-left"} {variant === "seat" ? "w-10 flex-none" : "w-full"}' class='wire-input-number__input'
/> />
{#if suffix !== ""} {#if suffix !== ""}
<span <span
aria-hidden="true" aria-hidden="true"
class='shrink-0 pl-1.5 text-[var(--wire-color-muted)]' class='wire-input-number__suffix'
> >
{suffix} {suffix}
</span> </span>
@@ -552,11 +553,11 @@ component InputNumber {
aria-controls='{inputId()}' aria-controls='{inputId()}'
disabled='{incrementDisabled()}' disabled='{incrementDisabled()}'
@click='incrementValue(event)' @click='incrementValue(event)'
class='inline-flex shrink-0 items-center justify-center border-l border-[var(--wire-color-border)] bg-transparent text-[var(--wire-color-muted)] transition-[color,background-color] duration-[var(--wire-motion-fast)] hover:bg-[var(--wire-color-surface-2)] hover:text-[var(--input-number-accent)] focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--input-number-accent)] disabled:cursor-not-allowed disabled:opacity-40 {size === "xs" ? "w-8" : size === "sm" ? "w-9" : size === "lg" ? "w-12" : size === "xl" ? "w-14" : "w-10"}' class='wire-input-number__button wire-input-number__button--end'
> >
<span <span
aria-hidden="true" aria-hidden="true"
class='icon-[lucide--plus] size-4' class='icon-[lucide--plus] wire-input-number__icon'
></span> ></span>
</button> </button>
{:else} {:else}
@@ -564,7 +565,7 @@ component InputNumber {
<div <div
role="group" role="group"
aria-label='{controlsLabel}' aria-label='{controlsLabel}'
class='flex shrink-0 border-l border-[var(--wire-color-border)] {variant === "vertical" ? "flex-col" : "flex-row"}' class='wire-input-number__buttons'
> >
<button <button
type="button" type="button"
@@ -572,11 +573,11 @@ component InputNumber {
aria-controls='{inputId()}' aria-controls='{inputId()}'
disabled='{decrementDisabled()}' disabled='{decrementDisabled()}'
@click='decrementValue(event)' @click='decrementValue(event)'
class='inline-flex items-center justify-center bg-transparent text-[var(--wire-color-muted)] transition-[color,background-color] duration-[var(--wire-motion-fast)] hover:bg-[var(--wire-color-surface-2)] hover:text-[var(--input-number-accent)] focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--input-number-accent)] disabled:cursor-not-allowed disabled:opacity-40 {variant === "vertical" ? "flex-1 border-b border-[var(--wire-color-border)]" : "border-r border-[var(--wire-color-border)]"} {size === "xs" ? "w-8" : size === "sm" ? "w-9" : size === "lg" ? "w-12" : size === "xl" ? "w-14" : "w-10"}' class='wire-input-number__button wire-input-number__button--decrement'
> >
<span <span
aria-hidden="true" aria-hidden="true"
class='icon-[lucide--minus] size-4' class='icon-[lucide--minus] wire-input-number__icon'
></span> ></span>
</button> </button>
@@ -586,11 +587,11 @@ component InputNumber {
aria-controls='{inputId()}' aria-controls='{inputId()}'
disabled='{incrementDisabled()}' disabled='{incrementDisabled()}'
@click='incrementValue(event)' @click='incrementValue(event)'
class='inline-flex items-center justify-center bg-transparent text-[var(--wire-color-muted)] transition-[color,background-color] duration-[var(--wire-motion-fast)] hover:bg-[var(--wire-color-surface-2)] hover:text-[var(--input-number-accent)] focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--input-number-accent)] disabled:cursor-not-allowed disabled:opacity-40 {variant === "vertical" ? "flex-1" : ""} {size === "xs" ? "w-8" : size === "sm" ? "w-9" : size === "lg" ? "w-12" : size === "xl" ? "w-14" : "w-10"}' class='wire-input-number__button wire-input-number__button--increment'
> >
<span <span
aria-hidden="true" aria-hidden="true"
class='icon-[lucide--plus] size-4' class='icon-[lucide--plus] wire-input-number__icon'
></span> ></span>
</button> </button>
</div> </div>
@@ -603,11 +604,11 @@ component InputNumber {
id='{messageId()}' id='{messageId()}'
role="alert" role="alert"
aria-live="polite" aria-live="polite"
class='m-0 flex items-center gap-1.5 text-xs leading-5 text-[var(--wire-color-danger)]' class='wire-input-number__message wire-input-number__message--error'
> >
<span <span
aria-hidden="true" aria-hidden="true"
class='icon-[lucide--circle-alert] size-3.5 shrink-0' class='icon-[lucide--circle-alert] wire-input-number__error-icon'
></span> ></span>
<span>{validationMessage()}</span> <span>{validationMessage()}</span>
</p> </p>
@@ -616,11 +617,66 @@ component InputNumber {
{#if (!showValidationMessage || !isInvalid() || validationMessage() === "") && helpText !== ""} {#if (!showValidationMessage || !isInvalid() || validationMessage() === "") && helpText !== ""}
<p <p
id='{messageId()}' id='{messageId()}'
class='m-0 text-xs leading-5 text-[var(--wire-color-muted)]' class='wire-input-number__message'
> >
{helpText} {helpText}
</p> </p>
{/if} {/if}
</div> </div>
} }
style {
.wire-input-number { position: relative; display: flex; width: 100%; max-width: 24rem; flex-direction: column; gap: 0.375rem; color: var(--wire-color-text); }
.wire-input-number[data-full-width="true"] { max-width: none; }
.wire-input-number[data-variant="compact"] { width: fit-content; max-width: 100%; }
.wire-input-number[data-disabled="true"] { opacity: 0.6; }
.wire-input-number__label { display: inline-flex; align-items: center; gap: 0.25rem; color: var(--wire-color-text); font-size: 0.875rem; font-weight: 600; line-height: 1.25rem; }
.wire-input-number__required { margin-left: 0.125rem; color: var(--wire-color-danger); }
.wire-input-number__description, .wire-input-number__message { margin: 0; color: var(--wire-color-muted); font-size: 0.75rem; line-height: 1.25rem; }
.wire-input-number__control { display: flex; min-width: 0; min-height: 2.5rem; overflow: hidden; border: 1px solid var(--wire-color-border); border-radius: var(--wire-radius-sm); color: var(--wire-color-text); background: var(--wire-color-surface); box-shadow: var(--wire-shadow-1); transition: border-color var(--wire-motion-base), box-shadow var(--wire-motion-base), background var(--wire-motion-base); }
.wire-input-number__control:focus-within { border-color: var(--input-number-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--input-number-accent) 18%, transparent); }
.wire-input-number[data-invalid="true"] .wire-input-number__control { border-color: var(--wire-color-danger); }
.wire-input-number[data-invalid="true"] .wire-input-number__control:focus-within { box-shadow: 0 0 0 3px color-mix(in srgb, var(--wire-color-danger) 18%, transparent); }
.wire-input-number[data-disabled="true"] .wire-input-number__control { cursor: not-allowed; background: var(--wire-color-surface-2); }
.wire-input-number[data-variant="compact"] .wire-input-number__control { border-radius: 999px; }
.wire-input-number[data-size="xs"] .wire-input-number__control { min-height: 2rem; font-size: 0.75rem; }
.wire-input-number[data-size="sm"] .wire-input-number__control { min-height: 2.25rem; font-size: 0.875rem; }
.wire-input-number[data-size="lg"] .wire-input-number__control { min-height: 3rem; font-size: 1rem; }
.wire-input-number[data-size="xl"] .wire-input-number__control { min-height: 3.5rem; font-size: 1.125rem; }
.wire-input-number__content { display: flex; min-width: 0; flex: 1; align-items: center; padding-inline: 0.75rem; }
.wire-input-number[data-size="xs"] .wire-input-number__content { padding-inline: 0.5rem; }
.wire-input-number[data-size="sm"] .wire-input-number__content { padding-inline: 0.625rem; }
.wire-input-number[data-size="lg"] .wire-input-number__content { padding-inline: 1rem; }
.wire-input-number[data-size="xl"] .wire-input-number__content { padding-inline: 1.25rem; }
.wire-input-number[data-variant="labeled"] .wire-input-number__content { flex-direction: column; align-items: stretch; justify-content: center; gap: 0.125rem; }
.wire-input-number[data-variant="seat"] .wire-input-number__content { justify-content: space-between; gap: 0.75rem; }
.wire-input-number__copy { min-width: 0; flex: 1; }
.wire-input-number__inner-label, .wire-input-number__inner-description { display: block; overflow: hidden; color: var(--wire-color-text); font-size: 0.875rem; font-weight: 600; line-height: 1rem; text-overflow: ellipsis; white-space: nowrap; }
.wire-input-number__inner-description { color: var(--wire-color-muted); font-size: 0.75rem; font-weight: 400; }
.wire-input-number[data-variant="labeled"] .wire-input-number__inner-label { color: var(--wire-color-muted); font-size: 0.75rem; font-weight: 500; }
.wire-input-number__field { display: flex; width: 100%; min-width: 0; align-items: center; }
.wire-input-number[data-variant="seat"] .wire-input-number__field { width: auto; flex: none; }
.wire-input-number__prefix, .wire-input-number__suffix { flex: none; color: var(--wire-color-muted); }
.wire-input-number__prefix { padding-right: 0.375rem; } .wire-input-number__suffix { padding-left: 0.375rem; }
.wire-input-number__input { width: 100%; min-width: 0; flex: 1; padding: 0; border: 0; outline: none; color: var(--wire-color-text); background: transparent; font: inherit; font-weight: 500; line-height: 1; appearance: textfield; }
.wire-input-number__input::-webkit-inner-spin-button, .wire-input-number__input::-webkit-outer-spin-button { appearance: none; }
.wire-input-number__input::placeholder { color: var(--wire-color-muted); }
.wire-input-number__input:read-only { cursor: default; }
.wire-input-number__input:disabled { cursor: not-allowed; }
.wire-input-number:is([data-variant="horizontal"], [data-variant="compact"], [data-variant="seat"]) .wire-input-number__input { text-align: center; }
.wire-input-number[data-variant="seat"] .wire-input-number__input { width: 2.5rem; flex: none; }
.wire-input-number__buttons { display: flex; flex: none; border-left: 1px solid var(--wire-color-border); }
.wire-input-number[data-variant="vertical"] .wire-input-number__buttons { flex-direction: column; }
.wire-input-number__button { display: inline-flex; width: 2.5rem; flex: none; align-items: center; justify-content: center; padding: 0; border: 0; color: var(--wire-color-muted); background: transparent; transition: color var(--wire-motion-fast), background var(--wire-motion-fast); }
.wire-input-number[data-size="xs"] .wire-input-number__button { width: 2rem; } .wire-input-number[data-size="sm"] .wire-input-number__button { width: 2.25rem; } .wire-input-number[data-size="lg"] .wire-input-number__button { width: 3rem; } .wire-input-number[data-size="xl"] .wire-input-number__button { width: 3.5rem; }
.wire-input-number__button--start { border-right: 1px solid var(--wire-color-border); } .wire-input-number__button--end { border-left: 1px solid var(--wire-color-border); }
.wire-input-number__button--decrement { border-right: 1px solid var(--wire-color-border); }
.wire-input-number[data-variant="vertical"] .wire-input-number__button--decrement { border-right: 0; border-bottom: 1px solid var(--wire-color-border); }
.wire-input-number__button:hover { color: var(--input-number-accent); background: var(--wire-color-surface-2); }
.wire-input-number__button:focus-visible { z-index: 1; outline: 2px solid var(--input-number-accent); outline-offset: -2px; }
.wire-input-number__button:disabled { cursor: not-allowed; opacity: 0.4; }
.wire-input-number__icon { width: 1rem; height: 1rem; }
.wire-input-number__message--error { display: flex; align-items: center; gap: 0.375rem; color: var(--wire-color-danger); }
.wire-input-number__error-icon { width: 0.875rem; height: 0.875rem; flex: none; }
}
} }
+19 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component LegendIndicator { component LegendIndicator {
outputs { outputs {
toggle(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) toggle(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
@@ -14,11 +16,27 @@ component LegendIndicator {
class: string = "" class: string = ""
} }
view { view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--legend-indicator wire-next--variant-{variant} {class}"> <section class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--legend-indicator wire-next--variant-{variant} {class}">
{#if title}<strong>{title}</strong>{/if} {#if title}<strong>{title}</strong>{/if}
{#if description}<p>{description}</p>{/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} {#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
<slot /> <slot />
</section> </section>
<ComponentBaseStyles hidden />
}
style {
.wire-next--legend-indicator {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius);
color: var(--wire-color-text);
background: var(--wire-color-surface);
}
.wire-next--legend-indicator > p { margin: 0; color: var(--wire-color-muted); }
.wire-next--legend-indicator > .wire-next__items { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.wire-next--legend-indicator > .wire-next__items > span { padding: 0.35rem 0.6rem; border-radius: var(--wire-radius-sm); background: var(--wire-color-surface-2); }
} }
} }
+56 -39
View File
@@ -17,89 +17,76 @@ component List {
<section <section
data-ui-component="List" data-ui-component="List"
aria-label='{title}' aria-label='{title}'
class='w-full {class}' class='wire-list {class}'
> >
{#if title || description} {#if title || description}
<header class="mb-4"> <header class="wire-list__header">
{#if title} {#if title}
<h3 class="text-lg font-bold text-[var(--wire-color-text)]">{title}</h3> <h3 class="wire-list__title">{title}</h3>
{/if} {/if}
{#if description} {#if description}
<p class="mt-1 text-sm leading-6 text-[var(--wire-color-text-muted)]">{description}</p> <p class="wire-list__description">{description}</p>
{/if} {/if}
</header> </header>
{/if} {/if}
<ul <ul
class="overflow-hidden" class="wire-list__items"
class:divide-y='variant === "default" || variant === "divided"' data-variant='{variant}'
class:divide-[var(--wire-color-border)]='variant === "default" || variant === "divided"'
class:rounded-2xl='variant === "card"'
class:border='variant === "card"'
class:border-[var(--wire-color-border)]='variant === "card"'
class:bg-[var(--wire-color-surface-raised)]='variant === "card"'
class:space-y-3='variant === "separated"'
> >
{#each items as item, index} {#each items as item, index}
<li <li
class="group min-w-0" class="wire-list__item"
class:rounded-xl='variant === "separated"' data-variant='{variant}'
class:border='variant === "separated"' @click='if (!item.href) { output.select({ item: item, index: index }) }'
class:border-[var(--wire-color-border)]='variant === "separated"'
class:bg-[var(--wire-color-surface-raised)]='variant === "separated"'
> >
{#if item.href} {#if item.href}
<a <a
href='{item.href}' href='{item.href}'
class="flex min-w-0 items-start gap-3 px-4 py-3 outline-none transition hover:bg-[var(--wire-color-surface-soft)] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--wire-color-focus)]" class="wire-list__row"
class:px-3='size === "sm"' data-size='{size}'
class:py-2.5='size === "sm"'
class:px-5='size === "lg"'
class:py-4='size === "lg"'
@click='output.select({ item: item, index: index })' @click='output.select({ item: item, index: index })'
> >
{#if item.icon} {#if item.icon}
<span class="flex size-10 shrink-0 items-center justify-center rounded-xl bg-[var(--wire-color-primary-soft)] text-[var(--wire-color-primary)]"> <span class="wire-list__leading-icon"><span class='{item.icon}' aria-hidden="true"></span>
<span class='{item.icon + " size-5"}' aria-hidden="true"></span>
</span> </span>
{/if} {/if}
{#if item.imageSrc} {#if item.imageSrc}
<img src='{item.imageSrc}' alt='{item.imageAlt || ""}' class="size-12 shrink-0 rounded-xl object-cover" loading="lazy" /> <img src='{item.imageSrc}' alt='{item.imageAlt || ""}' class="wire-list__image" loading="lazy" />
{/if} {/if}
<div class="min-w-0 flex-1"> <div class="wire-list__body">
<div class="flex items-start justify-between gap-3"> <div class="wire-list__heading">
<p class="truncate font-semibold text-[var(--wire-color-text)]">{item.title || item.label}</p> <p class="wire-list__item-title">{item.title || item.label}</p>
{#if item.meta} {#if item.meta}
<span class="shrink-0 text-xs text-[var(--wire-color-text-muted)]">{item.meta}</span> <span class="wire-list__meta">{item.meta}</span>
{/if} {/if}
</div> </div>
{#if item.description} {#if item.description}
<p class="mt-1 line-clamp-2 text-sm leading-5 text-[var(--wire-color-text-muted)]">{item.description}</p> <p class="wire-list__item-description">{item.description}</p>
{/if} {/if}
{#if item.badge} {#if item.badge}
<span class="mt-2 inline-flex rounded-full bg-[var(--wire-color-primary-soft)] px-2.5 py-1 text-xs font-semibold text-[var(--wire-color-primary)]">{item.badge}</span> <span class="wire-list__badge">{item.badge}</span>
{/if} {/if}
</div> </div>
<span class="icon-[lucide--chevron-right] mt-1 size-4 shrink-0 text-[var(--wire-color-text-muted)] transition group-hover:translate-x-0.5 group-hover:text-[var(--wire-color-primary)]" aria-hidden="true"></span> <span class="icon-[lucide--chevron-right] wire-list__chevron" aria-hidden="true"></span>
</a> </a>
{:else} {:else}
<div class="flex min-w-0 items-start gap-3 px-4 py-3"> <div class="wire-list__row" data-size='{size}'>
{#if item.icon} {#if item.icon}
<span class="flex size-10 shrink-0 items-center justify-center rounded-xl bg-[var(--wire-color-primary-soft)] text-[var(--wire-color-primary)]"> <span class="wire-list__leading-icon"><span class='{item.icon}' aria-hidden="true"></span>
<span class='{item.icon + " size-5"}' aria-hidden="true"></span>
</span> </span>
{/if} {/if}
<div class="min-w-0 flex-1"> <div class="wire-list__body">
<p class="font-semibold text-[var(--wire-color-text)]">{item.title || item.label}</p> <p class="wire-list__item-title">{item.title || item.label}</p>
{#if item.description} {#if item.description}
<p class="mt-1 text-sm leading-5 text-[var(--wire-color-text-muted)]">{item.description}</p> <p class="wire-list__item-description">{item.description}</p>
{/if} {/if}
</div> </div>
</div> </div>
{/if} {/if}
</li> </li>
{:empty} {:empty}
<li class="rounded-xl border border-dashed border-[var(--wire-color-border)] p-6 text-center text-sm text-[var(--wire-color-text-muted)]"> <li class="wire-list__empty">
No items available. No items available.
</li> </li>
{/each} {/each}
@@ -108,4 +95,34 @@ component List {
<slot></slot> <slot></slot>
</section> </section>
} }
style {
.wire-list { width: 100%; }
.wire-list__header { margin-bottom: 1rem; }
.wire-list__title { color: var(--wire-color-text); font-size: 1.125rem; font-weight: 700; }
.wire-list__description { margin-top: 0.25rem; color: var(--wire-color-text-muted); font-size: 0.875rem; line-height: 1.5rem; }
.wire-list__items { overflow: hidden; }
.wire-list__items:is([data-variant="default"], [data-variant="divided"]) > .wire-list__item + .wire-list__item { border-top: 1px solid var(--wire-color-border); }
.wire-list__items[data-variant="card"] { border: 1px solid var(--wire-color-border); border-radius: calc(var(--wire-radius) * 1.5); background: var(--wire-color-surface-raised); }
.wire-list__items[data-variant="separated"] { display: grid; gap: 0.75rem; }
.wire-list__item { min-width: 0; }
.wire-list__item[data-variant="separated"] { border: 1px solid var(--wire-color-border); border-radius: var(--wire-radius); background: var(--wire-color-surface-raised); }
.wire-list__row { display: flex; min-width: 0; align-items: flex-start; gap: 0.75rem; padding: 0.75rem 1rem; outline: none; transition: background var(--wire-motion-base); }
a.wire-list__row:hover { background: var(--wire-color-surface-soft); }
.wire-list__row:focus-visible { box-shadow: inset 0 0 0 2px var(--wire-color-focus); }
.wire-list__row[data-size="sm"] { padding: 0.625rem 0.75rem; }
.wire-list__row[data-size="lg"] { padding: 1rem 1.25rem; }
.wire-list__leading-icon { display: flex; width: 2.5rem; height: 2.5rem; flex: none; align-items: center; justify-content: center; border-radius: var(--wire-radius); color: var(--wire-color-primary); background: var(--wire-color-primary-soft); }
.wire-list__leading-icon > span { width: 1.25rem; height: 1.25rem; }
.wire-list__image { width: 3rem; height: 3rem; flex: none; border-radius: var(--wire-radius); object-fit: cover; }
.wire-list__body { min-width: 0; flex: 1; }
.wire-list__heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem; }
.wire-list__item-title { overflow: hidden; color: var(--wire-color-text); font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
.wire-list__meta { flex: none; color: var(--wire-color-text-muted); font-size: 0.75rem; }
.wire-list__item-description { display: -webkit-box; margin-top: 0.25rem; overflow: hidden; color: var(--wire-color-text-muted); font-size: 0.875rem; line-height: 1.25rem; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
.wire-list__badge { display: inline-flex; margin-top: 0.5rem; padding: 0.25rem 0.625rem; border-radius: 999px; color: var(--wire-color-primary); background: var(--wire-color-primary-soft); font-size: 0.75rem; font-weight: 600; }
.wire-list__chevron { width: 1rem; height: 1rem; flex: none; margin-top: 0.25rem; color: var(--wire-color-text-muted); transition: color var(--wire-motion-base), transform var(--wire-motion-base); }
.wire-list__row:hover .wire-list__chevron { color: var(--wire-color-primary); transform: translateX(0.125rem); }
.wire-list__empty { padding: 1.5rem; border: 1px dashed var(--wire-color-border); border-radius: var(--wire-radius); color: var(--wire-color-text-muted); font-size: 0.875rem; text-align: center; }
}
} }
+19 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component ListGroup { component ListGroup {
outputs { outputs {
select(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) select(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -14,11 +16,27 @@ component ListGroup {
class: string = "" class: string = ""
} }
view { view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--list-group wire-next--variant-{variant} {class}"> <section class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--list-group wire-next--variant-{variant} {class}">
{#if title}<strong>{title}</strong>{/if} {#if title}<strong>{title}</strong>{/if}
{#if description}<p>{description}</p>{/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} {#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
<slot /> <slot />
</section> </section>
<ComponentBaseStyles hidden />
}
style {
.wire-next--list-group {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius);
color: var(--wire-color-text);
background: var(--wire-color-surface);
}
.wire-next--list-group > p { margin: 0; color: var(--wire-color-muted); }
.wire-next--list-group > .wire-next__items { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.wire-next--list-group > .wire-next__items > span { padding: 0.35rem 0.6rem; border-radius: var(--wire-radius-sm); background: var(--wire-color-surface-2); }
} }
} }
+36 -18
View File
@@ -21,37 +21,34 @@ component Map {
<section <section
data-ui-component="Map" data-ui-component="Map"
aria-label='{title}' aria-label='{title}'
class='overflow-hidden rounded-2xl border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] shadow-sm {class}' class='wire-map {class}'
> >
{#if title || description} {#if title || description}
<header class="flex items-start justify-between gap-4 border-b border-[var(--wire-color-border)] p-5"> <header class="wire-map__header">
<div> <div>
{#if title} {#if title}
<h3 class="text-lg font-bold text-[var(--wire-color-text)]">{title}</h3> <h3 class="wire-map__title">{title}</h3>
{/if} {/if}
{#if description} {#if description}
<p class="mt-1 text-sm leading-6 text-[var(--wire-color-text-muted)]">{description}</p> <p class="wire-map__description">{description}</p>
{/if} {/if}
</div> </div>
<span class="flex size-10 shrink-0 items-center justify-center rounded-xl bg-[var(--wire-color-primary-soft)] text-[var(--wire-color-primary)]"> <span class="wire-map__header-icon"><span class="icon-[lucide--map]" aria-hidden="true"></span>
<span class="icon-[lucide--map] size-5" aria-hidden="true"></span>
</span> </span>
</header> </header>
{/if} {/if}
<div <div
class="relative isolate overflow-hidden bg-[var(--wire-color-surface-soft)]" class="wire-map__viewport"
class:h-64='size === "sm"' data-size='{size}'
class:h-80='size === "default" || size === "md"'
class:h-[28rem]='size === "lg"'
> >
<div <div
class="pointer-events-none absolute inset-0 opacity-50" class="wire-map__grid"
style="background-image: linear-gradient(var(--wire-color-border) 1px, transparent 1px), linear-gradient(90deg, var(--wire-color-border) 1px, transparent 1px); background-size: 32px 32px;" style="background-image: linear-gradient(var(--wire-color-border) 1px, transparent 1px), linear-gradient(90deg, var(--wire-color-border) 1px, transparent 1px); background-size: 32px 32px;"
aria-hidden="true" aria-hidden="true"
></div> ></div>
<div class="absolute inset-0 flex items-center justify-center p-6"> <div class="wire-map__content">
<slot></slot> <slot></slot>
</div> </div>
@@ -60,7 +57,7 @@ component Map {
<button <button
type="button" type="button"
aria-label='{item.label || item.title || "Map marker"}' aria-label='{item.label || item.title || "Map marker"}'
class="absolute inline-flex size-10 items-center justify-center rounded-full border-4 border-[var(--wire-color-surface-raised)] bg-[var(--wire-color-primary)] text-[var(--wire-color-on-primary)] shadow-lg transition hover:scale-110 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)]" class="wire-map__marker"
style='left: {item.x || (20 + index * 12)}%; top: {item.y || (30 + (index % 3) * 18)}%;' style='left: {item.x || (20 + index * 12)}%; top: {item.y || (30 + (index % 3) * 18)}%;'
@click='output.markerClick(item); output.select(item)' @click='output.markerClick(item); output.select(item)'
> >
@@ -69,25 +66,46 @@ component Map {
{/each} {/each}
{/if} {/if}
<div class="absolute bottom-4 right-4 flex flex-col gap-2"> <div class="wire-map__controls">
<button <button
type="button" type="button"
aria-label="Zoom in" aria-label="Zoom in"
class="inline-flex size-10 items-center justify-center rounded-xl border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] text-[var(--wire-color-text)] shadow-sm transition hover:bg-[var(--wire-color-surface-soft)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)]" class="wire-map__control"
@click='output.zoom({ direction: "in" })' @click='output.zoom({ direction: "in" })'
> >
<span class="icon-[lucide--plus] size-4" aria-hidden="true"></span> <span class="icon-[lucide--plus] wire-map__control-icon" aria-hidden="true"></span>
</button> </button>
<button <button
type="button" type="button"
aria-label="Zoom out" aria-label="Zoom out"
class="inline-flex size-10 items-center justify-center rounded-xl border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] text-[var(--wire-color-text)] shadow-sm transition hover:bg-[var(--wire-color-surface-soft)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)]" class="wire-map__control"
@click='output.zoom({ direction: "out" })' @click='output.zoom({ direction: "out" })'
> >
<span class="icon-[lucide--minus] size-4" aria-hidden="true"></span> <span class="icon-[lucide--minus] wire-map__control-icon" aria-hidden="true"></span>
</button> </button>
</div> </div>
</div> </div>
</section> </section>
} }
style {
.wire-map { overflow: hidden; border: 1px solid var(--wire-color-border); border-radius: calc(var(--wire-radius) * 1.5); background: var(--wire-color-surface-raised); box-shadow: var(--wire-shadow-1); }
.wire-map__header { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; padding: 1.25rem; border-bottom: 1px solid var(--wire-color-border); }
.wire-map__title { color: var(--wire-color-text); font-size: 1.125rem; font-weight: 700; }
.wire-map__description { margin-top: 0.25rem; color: var(--wire-color-text-muted); font-size: 0.875rem; line-height: 1.5rem; }
.wire-map__header-icon { display: flex; width: 2.5rem; height: 2.5rem; flex: none; align-items: center; justify-content: center; border-radius: var(--wire-radius); color: var(--wire-color-primary); background: var(--wire-color-primary-soft); }
.wire-map__header-icon > span { width: 1.25rem; height: 1.25rem; }
.wire-map__viewport { position: relative; isolation: isolate; height: 20rem; overflow: hidden; background: var(--wire-color-surface-soft); }
.wire-map__viewport[data-size="sm"] { height: 16rem; }
.wire-map__viewport[data-size="lg"] { height: 28rem; }
.wire-map__grid { position: absolute; inset: 0; opacity: 0.5; pointer-events: none; }
.wire-map__content { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 1.5rem; }
.wire-map__marker { position: absolute; display: inline-flex; width: 2.5rem; height: 2.5rem; align-items: center; justify-content: center; padding: 0; border: 4px solid var(--wire-color-surface-raised); border-radius: 50%; color: var(--wire-color-on-primary); background: var(--wire-color-primary); box-shadow: var(--wire-shadow-3); transition: transform var(--wire-motion-base) var(--wire-ease-standard); }
.wire-map__marker:hover { transform: scale(1.1); }
.wire-map__controls { position: absolute; right: 1rem; bottom: 1rem; display: flex; flex-direction: column; gap: 0.5rem; }
.wire-map__control { display: inline-flex; width: 2.5rem; height: 2.5rem; align-items: center; justify-content: center; padding: 0; border: 1px solid var(--wire-color-border); border-radius: var(--wire-radius); color: var(--wire-color-text); background: var(--wire-color-surface-raised); box-shadow: var(--wire-shadow-1); transition: background var(--wire-motion-base); }
.wire-map__control:hover { background: var(--wire-color-surface-soft); }
.wire-map__marker:focus-visible, .wire-map__control:focus-visible { outline: 2px solid var(--wire-color-focus); outline-offset: 2px; }
.wire-map__control-icon { width: 1rem; height: 1rem; }
}
} }
+38 -21
View File
@@ -21,46 +21,44 @@ component Marquee {
<section <section
data-ui-component="Marquee" data-ui-component="Marquee"
aria-label='{title}' aria-label='{title}'
class='overflow-hidden border-y border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] {class}' class='wire-marquee {class}'
> >
<div class="flex items-stretch"> <div class="wire-marquee__layout">
{#if title} {#if title}
<div class="relative z-10 flex shrink-0 items-center gap-2 border-r border-[var(--wire-color-border)] bg-[var(--wire-color-primary)] px-4 py-3 text-[var(--wire-color-on-primary)] sm:px-5"> <div class="wire-marquee__title">
<span class="icon-[lucide--megaphone] size-4" aria-hidden="true"></span> <span class="icon-[lucide--megaphone] wire-marquee__icon" aria-hidden="true"></span>
<span class="text-sm font-bold">{title}</span> <span>{title}</span>
</div> </div>
{/if} {/if}
<div <div
class="group relative min-w-0 flex-1 overflow-hidden" class="wire-marquee__window"
@mouseenter='paused = true; output.pause({})' @mouseenter='paused = true; output.pause({})'
@mouseleave='paused = false; output.resume({})' @mouseleave='paused = false; output.resume({})'
@focusin='paused = true' @focusin='paused = true'
@focusout='paused = false' @focusout='paused = false'
> >
<div <div
class="wire-marquee-track flex w-max min-w-full items-center" class="wire-marquee__track"
class:wire-marquee-paused='paused' class:wire-marquee-paused='paused'
> >
{#each items as item} {#each items as item}
<a <a
href='{item.href || "#"}' href='{item.href || "#"}'
class="flex shrink-0 items-center gap-3 px-5 py-3 text-sm font-medium text-[var(--wire-color-text)] transition hover:bg-[var(--wire-color-primary-soft)] hover:text-[var(--wire-color-primary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--wire-color-focus)]" class="wire-marquee__item"
> >
<span <span
class="size-2 shrink-0 rounded-full bg-[var(--wire-color-primary)]" class="wire-marquee__dot"
class:bg-[var(--wire-color-danger)]='item.color === "danger"' data-color='{item.color || "primary"}'
class:bg-[var(--wire-color-warning)]='item.color === "warning"'
class:bg-[var(--wire-color-success)]='item.color === "success"'
aria-hidden="true" aria-hidden="true"
></span> ></span>
<span>{item.label || item.title}</span> <span>{item.label || item.title}</span>
{#if item.meta} {#if item.meta}
<span class="text-xs text-[var(--wire-color-text-muted)]">{item.meta}</span> <span class="wire-marquee__meta">{item.meta}</span>
{/if} {/if}
</a> </a>
{:empty} {:empty}
<p class="px-5 py-3 text-sm text-[var(--wire-color-text-muted)]">{description || "No announcements available."}</p> <p class="wire-marquee__empty">{description || "No announcements available."}</p>
{/each} {/each}
{#if items.length > 0} {#if items.length > 0}
@@ -69,9 +67,9 @@ component Marquee {
href='{item.href || "#"}' href='{item.href || "#"}'
aria-hidden="true" aria-hidden="true"
tabindex="-1" tabindex="-1"
class="flex shrink-0 items-center gap-3 px-5 py-3 text-sm font-medium text-[var(--wire-color-text)]" class="wire-marquee__item"
> >
<span class="size-2 shrink-0 rounded-full bg-[var(--wire-color-primary)]" aria-hidden="true"></span> <span class="wire-marquee__dot" aria-hidden="true"></span>
<span>{item.label || item.title}</span> <span>{item.label || item.title}</span>
</a> </a>
{/each} {/each}
@@ -82,11 +80,11 @@ component Marquee {
<button <button
type="button" type="button"
aria-label='{paused ? "Resume announcements" : "Pause announcements"}' aria-label='{paused ? "Resume announcements" : "Pause announcements"}'
class="flex shrink-0 items-center justify-center border-l border-[var(--wire-color-border)] px-4 text-[var(--wire-color-text-muted)] transition hover:bg-[var(--wire-color-surface-soft)] hover:text-[var(--wire-color-text)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--wire-color-focus)]" class="wire-marquee__toggle"
@click='paused = !paused; paused ? output.pause({}) : output.resume({})' @click='paused = !paused; paused ? output.pause({}) : output.resume({})'
> >
<span class="icon-[lucide--pause] size-4" data-show='!paused' aria-hidden="true"></span> <span class="icon-[lucide--pause] wire-marquee__icon" data-show='!paused' aria-hidden="true"></span>
<span class="icon-[lucide--play] size-4" data-show='paused' aria-hidden="true"></span> <span class="icon-[lucide--play] wire-marquee__icon" data-show='paused' aria-hidden="true"></span>
</button> </button>
</div> </div>
@@ -95,9 +93,28 @@ component Marquee {
} }
style { style {
.wire-marquee-track { .wire-marquee { overflow: hidden; border-block: 1px solid var(--wire-color-border); background: var(--wire-color-surface-raised); }
.wire-marquee__layout { display: flex; align-items: stretch; }
.wire-marquee__title { position: relative; z-index: 1; display: flex; flex: none; align-items: center; gap: 0.5rem; padding: 0.75rem 1rem; border-right: 1px solid var(--wire-color-border); color: var(--wire-color-on-primary); background: var(--wire-color-primary); font-size: 0.875rem; font-weight: 700; }
.wire-marquee__window { position: relative; min-width: 0; flex: 1; overflow: hidden; }
.wire-marquee__track {
display: flex; width: max-content; min-width: 100%; align-items: center;
animation: wire-marquee 32s linear infinite; animation: wire-marquee 32s linear infinite;
} }
.wire-marquee-paused { animation-play-state: paused; }
.wire-marquee__item { display: flex; flex: none; align-items: center; gap: 0.75rem; padding: 0.75rem 1.25rem; color: var(--wire-color-text); font-size: 0.875rem; font-weight: 500; transition: color var(--wire-motion-base), background var(--wire-motion-base); }
.wire-marquee__item:hover { color: var(--wire-color-primary); background: var(--wire-color-primary-soft); }
.wire-marquee__item:focus-visible, .wire-marquee__toggle:focus-visible { outline: 2px solid var(--wire-color-focus); outline-offset: -2px; }
.wire-marquee__dot { width: 0.5rem; height: 0.5rem; flex: none; border-radius: 50%; background: var(--wire-color-primary); }
.wire-marquee__dot[data-color="danger"] { background: var(--wire-color-danger); }
.wire-marquee__dot[data-color="warning"] { background: var(--wire-color-warning); }
.wire-marquee__dot[data-color="success"] { background: var(--wire-color-success); }
.wire-marquee__meta { color: var(--wire-color-text-muted); font-size: 0.75rem; }
.wire-marquee__empty { padding: 0.75rem 1.25rem; color: var(--wire-color-text-muted); font-size: 0.875rem; }
.wire-marquee__toggle { display: flex; flex: none; align-items: center; justify-content: center; padding-inline: 1rem; border: 0; border-left: 1px solid var(--wire-color-border); color: var(--wire-color-text-muted); background: transparent; transition: color var(--wire-motion-base), background var(--wire-motion-base); }
.wire-marquee__toggle:hover { color: var(--wire-color-text); background: var(--wire-color-surface-soft); }
.wire-marquee__icon { width: 1rem; height: 1rem; }
@media (min-width: 40rem) { .wire-marquee__title { padding-inline: 1.25rem; } }
.wire-marquee-paused { .wire-marquee-paused {
animation-play-state: paused; animation-play-state: paused;
@@ -109,7 +126,7 @@ component Marquee {
} }
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {
.wire-marquee-track { .wire-marquee__track {
animation: none; animation: none;
} }
} }
+4 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Navbar { component Navbar {
outputs { outputs {
toggle(payload: { open: boolean }) toggle(payload: { open: boolean })
@@ -60,7 +62,7 @@ size: string = "default"
} }
view { view {
<header class="wire-navbar wire-navbar--width-{maxWidth} wire-next--color-{color} wire-next--size-{size} {sticky ? 'wire-navbar--sticky' : ''} {class}" data-wrn-navbar data-open-on-hover="{openOnHover}"> <header class="wire-navbar wire-navbar--width-{maxWidth} wire-component--color-{color} wire-component--size-{size} {sticky ? 'wire-navbar--sticky' : ''} {class}" data-wrn-navbar data-open-on-hover="{openOnHover}">
<div class="wire-navbar__topbar" aria-label="{topbarLabel}"> <div class="wire-navbar__topbar" aria-label="{topbarLabel}">
<slot name="topbar" /> <slot name="topbar" />
</div> </div>
@@ -139,6 +141,7 @@ size: string = "default"
</div> </div>
</div> </div>
</header> </header>
<ComponentBaseStyles hidden />
} }
style { style {
+125 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component PinInput { component PinInput {
outputs { outputs {
input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -49,7 +51,7 @@ component PinInput {
view { view {
<fieldset <fieldset
{...attrs} {...attrs}
class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--pin-input {invalid ? 'wire-next--invalid' : ''} {disabled ? 'wire-next--disabled' : ''} {class}" class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--pin-input {invalid ? 'wire-next--invalid' : ''} {disabled ? 'wire-next--disabled' : ''} {class}"
data-wrn-pin-input data-wrn-pin-input
data-length="{length}" data-length="{length}"
data-pattern="{pattern}" data-pattern="{pattern}"
@@ -113,5 +115,127 @@ component PinInput {
data-error="{name}" data-error="{name}"
>{validationMessage}</small> >{validationMessage}</small>
</fieldset> </fieldset>
<ComponentBaseStyles hidden />
}
style {
.wire-next--pin-input.wire-next--invalid .wire-next__pin-cells input,
.wire-next--pin-input:has(input.wire-invalid) .wire-next__pin-cells input {
border-color: var(--wire-color-danger);
}
.wire-next--pin-input {
display: grid;
width: 100%;
min-width: 0;
gap: 0.65rem;
padding: 0;
border: 0;
color: var(--wire-color-text);
}
.wire-next__pin-heading {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
.wire-next__pin-heading legend {
padding: 0;
font-size: 0.82em;
font-weight: 700;
}
.wire-next__pin-clear {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0;
border: 0;
color: var(--wire-component-color);
background: transparent;
font: inherit;
font-size: 0.7em;
font-weight: 750;
cursor: pointer;
}
.wire-next__pin-clear > span:first-child {
width: 0.9rem;
height: 0.9rem;
}
.wire-next__pin-cells {
display: flex;
max-width: 100%;
align-items: center;
gap: clamp(0.35rem, 1.5vw, 0.65rem);
overflow-x: auto;
padding: 0.2rem;
scrollbar-width: thin;
}
.wire-next--pin-input .wire-next__pin-cells input {
flex: 0 0 clamp(2.4rem, 8vw, 3.25rem);
width: clamp(2.4rem, 8vw, 3.25rem);
height: clamp(2.75rem, 9vw, 3.5rem);
min-width: clamp(2.4rem, 8vw, 3.25rem);
padding: 0;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-sm);
color: var(--wire-color-text);
background: var(--wire-color-bg);
font: inherit;
font-size: clamp(1rem, 3vw, 1.25rem);
font-weight: 750;
text-align: center;
caret-color: var(--wire-component-color);
transition:
border-color var(--wire-motion-base) var(--wire-ease-standard),
box-shadow var(--wire-motion-base) var(--wire-ease-standard),
transform var(--wire-motion-fast) var(--wire-ease-standard);
}
.wire-next--pin-input .wire-next__pin-cells input::placeholder {
color: var(--wire-color-muted);
opacity: 0.45;
}
.wire-next--pin-input .wire-next__pin-cells input:focus-visible {
border-color: var(--wire-component-color);
outline: 0;
box-shadow: 0 0 0 3px color-mix(in srgb, var(--wire-component-color) 18%, transparent);
transform: translateY(-1px);
}
.wire-next--pin-input .wire-next__pin-cells input:disabled,
.wire-next--pin-input .wire-next__pin-cells input:read-only {
cursor: not-allowed;
opacity: 0.55;
}
.wire-next__pin-separator {
color: var(--wire-color-muted);
font-size: 1.1rem;
font-weight: 800;
}
.wire-next--pin-input[data-complete="true"] .wire-next__pin-cells input {
border-color: color-mix(in srgb, var(--wire-component-color) 72%, var(--wire-color-border));
background: color-mix(in srgb, var(--wire-component-color) 7%, var(--wire-color-bg));
}
@media (max-width: 480px) {
.wire-next__pin-cells {
gap: 0.3rem;
}
.wire-next--pin-input .wire-next__pin-cells input {
flex-basis: min(2.7rem, 12vw);
width: min(2.7rem, 12vw);
min-width: min(2.7rem, 12vw);
height: min(3rem, 14vw);
}
}
} }
} }
+144 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component RangeSlider { component RangeSlider {
outputs { outputs {
input(payload: ({ value: number; name: string; sourceEvent: Event }) | ({ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])) input(payload: ({ value: number; name: string; sourceEvent: Event }) | ({ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]))
@@ -49,7 +53,7 @@ component RangeSlider {
client function increaseValue(sourceEvent) { currentValue = Math.min(Number(max), Number(currentValue) + Number(step)); output.input({ value: currentValue, name: name, sourceEvent: sourceEvent }); output.change({ value: currentValue, name: name, sourceEvent: sourceEvent }) } client function increaseValue(sourceEvent) { currentValue = Math.min(Number(max), Number(currentValue) + Number(step)); output.input({ value: currentValue, name: name, sourceEvent: sourceEvent }); output.change({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
} }
view { view {
<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 {...attrs} class="wire-component wire-component--color-{color} wire-component--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__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}"> <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} {#if icon}<span class="{icon}" aria-hidden="true"></span>{/if}
@@ -67,5 +71,144 @@ component RangeSlider {
</div> </div>
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small> {#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div> </div>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next__range-track {
display: grid;
flex: 1;
min-width: 0;
gap: 0.35rem;
}
.wire-next__range-control input {
width: 100%;
min-width: 0;
margin: 0;
flex: 1;
accent-color: var(--wire-field-color);
}
.wire-next__custom-slider {
position: relative;
width: 100%;
height: 1.5rem;
cursor: pointer;
touch-action: none;
}
.wire-next__custom-slider::before,
.wire-next__slider-fill {
position: absolute;
top: 50%;
height: 0.4rem;
border-radius: 999px;
transform: translateY(-50%);
content: "";
}
.wire-next__custom-slider::before {
right: 0;
left: 0;
background: var(--wire-color-surface-2);
box-shadow: inset 0 0 0 1px var(--wire-color-border);
}
.wire-next__slider-fill {
z-index: 1;
left: 0;
width: var(--wire-range-progress);
background: var(--wire-field-color);
}
.wire-next__slider-thumb {
position: absolute;
z-index: 3;
top: 50%;
left: var(--wire-range-progress);
width: 1.25rem;
height: 1.25rem;
border: 3px solid var(--wire-field-color);
border-radius: 50%;
background: var(--wire-color-surface);
box-shadow: var(--wire-shadow-1);
transform: translate(-50%, -50%);
}
.wire-next__custom-slider:focus-visible {
outline: 3px solid color-mix(in srgb, var(--wire-field-color) 28%, transparent);
outline-offset: 3px;
}
.wire-next__slider-marks button {
position: absolute;
z-index: 2;
top: 50%;
width: 0.55rem;
height: 0.55rem;
padding: 0;
border: 2px solid var(--wire-color-surface);
border-radius: 50%;
background: var(--wire-color-muted);
transform: translate(-50%, -50%);
}
.wire-next__range-control[data-show-steps="true"] input {
background-image: repeating-linear-gradient(
90deg,
transparent 0,
transparent calc(10% - 1px),
var(--wire-color-border) calc(10% - 1px),
var(--wire-color-border) 10%
);
}
.wire-next__range-bounds {
display: grid;
grid-template-columns: 1fr auto 1fr;
color: var(--wire-color-muted);
font-size: 0.78em;
font-variant-numeric: tabular-nums;
}
.wire-next__range-bounds span:nth-child(2) {
text-align: center;
}
.wire-next__range-bounds span:last-child {
text-align: right;
}
.wire-next__range-control output {
min-width: 3ch;
font-variant-numeric: tabular-nums;
}
.wire-next__range-stepper {
display: inline-grid;
width: 2.35rem;
height: 2.35rem;
flex: 0 0 auto;
place-items: center;
border: 1px solid var(--wire-color-border);
border-radius: 50%;
background: var(--wire-color-surface);
color: var(--wire-color-text);
font: inherit;
font-size: 1.2rem;
cursor: pointer;
}
.wire-next__range-stepper:hover:not(:disabled) {
border-color: var(--wire-field-color);
color: var(--wire-field-color);
}
.wire-next__range-stepper:disabled {
cursor: not-allowed;
opacity: 0.45;
}
} }
} }
+19 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Rating { component Rating {
outputs { outputs {
input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -14,11 +16,27 @@ component Rating {
class: string = "" class: string = ""
} }
view { view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--rating wire-next--variant-{variant} {class}"> <section class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--rating wire-next--variant-{variant} {class}">
{#if title}<strong>{title}</strong>{/if} {#if title}<strong>{title}</strong>{/if}
{#if description}<p>{description}</p>{/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} {#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
<slot /> <slot />
</section> </section>
<ComponentBaseStyles hidden />
}
style {
.wire-next--rating {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius);
color: var(--wire-color-text);
background: var(--wire-color-surface);
}
.wire-next--rating > p { margin: 0; color: var(--wire-color-muted); }
.wire-next--rating > .wire-next__items { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.wire-next--rating > .wire-next__items > span { padding: 0.35rem 0.6rem; border-radius: var(--wire-radius-sm); background: var(--wire-color-surface-2); }
} }
} }
+78 -13
View File
@@ -26,19 +26,19 @@ component SearchBox {
<form <form
data-ui-component="SearchBox" data-ui-component="SearchBox"
role="search" role="search"
class='w-full {class}' class='wire-search-box {class}'
@submit='event.preventDefault(); output.search({ value: query, name: name })' @submit='event.preventDefault(); output.search({ value: query, name: name })'
> >
<label <label
class="mb-2 block text-sm font-semibold text-[var(--wire-color-text)]" class="wire-search-box__label"
class:sr-only='label === ""' data-hidden='{label === "" ? "true" : "false"}'
> >
{label} {label}
</label> </label>
<div class="relative flex items-center"> <div class="wire-search-box__control">
<span <span
class="icon-[lucide--search] pointer-events-none absolute left-4 size-5 text-[var(--wire-color-input-placeholder)]" class="icon-[lucide--search] wire-search-box__search-icon"
aria-hidden="true" aria-hidden="true"
></span> ></span>
@@ -53,10 +53,8 @@ component SearchBox {
disabled='{disabled}' disabled='{disabled}'
required='{required}' required='{required}'
autocomplete="off" autocomplete="off"
class="w-full rounded-xl border border-[var(--wire-color-input-border)] bg-[var(--wire-color-input-background)] pl-12 pr-24 text-[var(--wire-color-input-text)] outline-none transition placeholder:text-[var(--wire-color-input-placeholder)] hover:border-[var(--wire-color-input-border-hover)] focus:border-[var(--wire-color-input-border-focus)] focus:ring-2 focus:ring-[var(--wire-color-focus)] disabled:cursor-not-allowed disabled:opacity-60" class="wire-search-box__input"
class:h-10='size === "sm"' data-size='{size}'
class:h-12='size === "default" || size === "md"'
class:h-14='size === "lg"'
@input='query = event.target.value' @input='query = event.target.value'
@change='query = event.target.value' @change='query = event.target.value'
/> />
@@ -65,21 +63,88 @@ component SearchBox {
type="button" type="button"
aria-label="Clear search" aria-label="Clear search"
data-show='query.length > 0 && !disabled' data-show='query.length > 0 && !disabled'
class="absolute right-12 inline-flex size-8 items-center justify-center rounded-lg text-[var(--wire-color-text-muted)] transition hover:bg-[var(--wire-color-surface-soft)] hover:text-[var(--wire-color-text)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)]" class="wire-search-box__button wire-search-box__clear"
@click='query = ""; event.currentTarget.parentElement.querySelector("input")?.focus(); output.clear({ value: "", name: name })' @click='query = ""; event.currentTarget.parentElement.querySelector("input")?.focus(); output.clear({ value: "", name: name })'
> >
<span class="icon-[lucide--x] size-4" aria-hidden="true"></span> <span class="icon-[lucide--x] wire-search-box__button-icon" aria-hidden="true"></span>
</button> </button>
<button <button
type="submit" type="submit"
aria-label='{label || "Search"}' aria-label='{label || "Search"}'
disabled='{disabled}' disabled='{disabled}'
class="absolute right-2 inline-flex size-9 items-center justify-center rounded-lg bg-[var(--wire-color-primary)] text-[var(--wire-color-on-primary)] transition hover:bg-[var(--wire-color-primary-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)] disabled:cursor-not-allowed disabled:opacity-60" class="wire-search-box__button wire-search-box__submit"
> >
<span class="icon-[lucide--arrow-right] size-4" aria-hidden="true"></span> <span class="icon-[lucide--arrow-right] wire-search-box__button-icon" aria-hidden="true"></span>
</button> </button>
</div> </div>
</form> </form>
} }
style {
.wire-search-box { width: 100%; }
.wire-search-box__label {
display: block;
margin-bottom: 0.5rem;
color: var(--wire-color-text);
font-size: 0.875rem;
font-weight: 600;
}
.wire-search-box__label[data-hidden="true"] {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.wire-search-box__control { position: relative; display: flex; align-items: center; }
.wire-search-box__search-icon {
position: absolute;
left: 1rem;
width: 1.25rem;
height: 1.25rem;
color: var(--wire-color-input-placeholder);
pointer-events: none;
}
.wire-search-box__input {
width: 100%;
height: 3rem;
padding: 0 6rem 0 3rem;
border: 1px solid var(--wire-color-input-border);
border-radius: var(--wire-radius);
outline: none;
color: var(--wire-color-input-text);
background: var(--wire-color-input-background);
transition: border-color var(--wire-motion-base) var(--wire-ease-standard), box-shadow var(--wire-motion-base) var(--wire-ease-standard);
}
.wire-search-box__input[data-size="sm"] { height: 2.5rem; }
.wire-search-box__input[data-size="lg"] { height: 3.5rem; }
.wire-search-box__input::placeholder { color: var(--wire-color-input-placeholder); }
.wire-search-box__input:hover { border-color: var(--wire-color-input-border-hover); }
.wire-search-box__input:focus {
border-color: var(--wire-color-input-border-focus);
box-shadow: 0 0 0 2px var(--wire-color-focus);
}
.wire-search-box__input:disabled, .wire-search-box__button:disabled { cursor: not-allowed; opacity: 0.6; }
.wire-search-box__button {
position: absolute;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
border: 0;
border-radius: var(--wire-radius-sm);
transition: color var(--wire-motion-base), background var(--wire-motion-base);
}
.wire-search-box__clear { right: 3rem; width: 2rem; height: 2rem; color: var(--wire-color-text-muted); background: transparent; }
.wire-search-box__clear:hover { color: var(--wire-color-text); background: var(--wire-color-surface-soft); }
.wire-search-box__submit { right: 0.5rem; width: 2.25rem; height: 2.25rem; color: var(--wire-color-on-primary); background: var(--wire-color-primary); }
.wire-search-box__submit:hover { background: var(--wire-color-primary-hover); }
.wire-search-box__button:focus-visible { outline: 2px solid var(--wire-color-focus); outline-offset: 2px; }
.wire-search-box__button-icon { width: 1rem; height: 1rem; }
}
} }
+200 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component StrongPassword { component StrongPassword {
outputs { outputs {
input(payload: { value: string; score: number; maximumScore: number; percent: number; level: string }) input(payload: { value: string; score: number; maximumScore: number; percent: number; level: string })
@@ -117,7 +121,7 @@ component StrongPassword {
view { view {
<div <div
class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--strong-password wire-next--strong-password-{presentation} {invalid ? 'wire-next--invalid' : ''} {disabled ? 'wire-next--disabled' : ''} {class}" class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--strong-password wire-next--strong-password-{presentation} {invalid ? 'wire-next--invalid' : ''} {disabled ? 'wire-next--disabled' : ''} {class}"
data-wrn-strong-password data-wrn-strong-password
data-strength="{password ? strengthLevel() : 'empty'}" data-strength="{password ? strengthLevel() : 'empty'}"
data-score="{password ? score() : 0}" data-score="{password ? score() : 0}"
@@ -214,5 +218,200 @@ component StrongPassword {
<small id="{name}-validation" class="wire-next__validation" data-error="{name}">{validationMessage}</small> <small id="{name}-validation" class="wire-next__validation" data-error="{name}">{validationMessage}</small>
</div> </div>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next--strong-password {
position: relative;
display: grid;
width: 100%;
gap: 0.6rem;
color: var(--wire-color-text);
}
.wire-next--strong-password > label {
font-size: 0.82em;
font-weight: 700;
}
.wire-next__strong-password-anchor {
position: relative;
}
.wire-next--strong-password input {
width: 100%;
min-height: 2.75em;
padding: 0.68em 0.85em;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-sm);
outline: 0;
color: var(--wire-color-text);
background: var(--wire-color-surface);
font: inherit;
transition:
border-color 160ms ease,
box-shadow 160ms ease;
}
.wire-next--strong-password input:focus-visible {
border-color: var(--wire-component-color);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--wire-component-color) 16%, transparent);
}
.wire-next__strong-password-details {
display: grid;
gap: 0.65rem;
}
.wire-next__strong-password-summary {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
color: var(--wire-color-muted);
font-size: 0.75em;
}
.wire-next__strong-password-summary strong {
color: var(--wire-color-text);
}
.wire-next__strong-password-meter {
width: 100%;
height: 0.42rem;
overflow: hidden;
border-radius: 999px;
background: color-mix(in srgb, var(--wire-color-border) 72%, transparent);
}
.wire-next__strong-password-meter > span {
display: block;
width: 0;
height: 100%;
border-radius: inherit;
background: var(--wire-color-danger);
transition:
width 180ms ease,
background-color 180ms ease;
}
.wire-next--strong-password[data-strength="fair"] .wire-next__strong-password-meter > span {
background: var(--wire-color-warning);
}
.wire-next--strong-password[data-strength="good"] .wire-next__strong-password-meter > span {
background: var(--wire-component-color);
}
.wire-next--strong-password[data-strength="strong"] .wire-next__strong-password-meter > span {
background: var(--wire-color-success);
}
.wire-next__strong-password-requirements {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.45rem 1rem;
margin: 0;
padding: 0;
list-style: none;
}
.wire-next__strong-password-requirements li {
display: flex;
min-width: 0;
align-items: flex-start;
gap: 0.45rem;
color: var(--wire-color-muted);
font-size: 0.72em;
line-height: 1.45;
}
.wire-next__strong-password-requirements li > span {
position: relative;
width: 0.9rem;
height: 0.9rem;
flex: 0 0 auto;
margin-top: 0.08rem;
border: 1px solid currentColor;
border-radius: 50%;
}
.wire-next__strong-password-requirements li > span::after {
position: absolute;
top: 0.12rem;
left: 0.29rem;
width: 0.22rem;
height: 0.42rem;
border: solid var(--wire-color-surface);
border-width: 0 0.1rem 0.1rem 0;
content: "";
opacity: 0;
transform: rotate(45deg);
}
.wire-next__strong-password-requirements li[data-met="true"] {
color: var(--wire-color-success);
}
.wire-next__strong-password-requirements li[data-met="true"] > span {
border-color: var(--wire-color-success);
background: var(--wire-color-success);
}
.wire-next__strong-password-requirements li[data-met="true"] > span::after {
opacity: 1;
}
.wire-next__strong-password-details > small {
color: var(--wire-color-muted);
font-size: 0.7em;
line-height: 1.5;
}
.wire-next__strong-password-popover {
position: absolute;
top: calc(100% + 0.7rem);
left: 0;
z-index: 30;
width: min(28rem, calc(100vw - 2rem));
padding: 1rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius);
opacity: 0;
visibility: hidden;
background: var(--wire-color-surface);
box-shadow: var(--wire-shadow-2);
transform: translateY(-0.35rem);
transition:
opacity 140ms ease,
transform 140ms ease,
visibility 140ms ease;
}
.wire-next__strong-password-popover[data-open="true"] {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.wire-next__strong-password-popover-arrow {
position: absolute;
top: -0.38rem;
left: 1.25rem;
width: 0.7rem;
height: 0.7rem;
border-top: 1px solid var(--wire-color-border);
border-left: 1px solid var(--wire-color-border);
background: var(--wire-color-surface);
transform: rotate(45deg);
}
@media (max-width: 560px) {
.wire-next__strong-password-requirements {
grid-template-columns: 1fr;
}
}
} }
} }
+19 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component StyledIcon { component StyledIcon {
props { props {
size: string = "default" size: string = "default"
@@ -9,11 +11,27 @@ component StyledIcon {
class: string = "" class: string = ""
} }
view { view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--styled-icon wire-next--variant-{variant} {class}"> <section class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--styled-icon wire-next--variant-{variant} {class}">
{#if title}<strong>{title}</strong>{/if} {#if title}<strong>{title}</strong>{/if}
{#if description}<p>{description}</p>{/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} {#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
<slot /> <slot />
</section> </section>
<ComponentBaseStyles hidden />
}
style {
.wire-next--styled-icon {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius);
color: var(--wire-color-text);
background: var(--wire-color-surface);
}
.wire-next--styled-icon > p { margin: 0; color: var(--wire-color-muted); }
.wire-next--styled-icon > .wire-next__items { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.wire-next--styled-icon > .wire-next__items > span { padding: 0.35rem 0.6rem; border-radius: var(--wire-radius-sm); background: var(--wire-color-surface-2); }
} }
} }
+33 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component TimePicker { component TimePicker {
outputs { outputs {
input(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]) input(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])
@@ -51,7 +55,7 @@ size: string = "default"
client function handleInvalid(sourceEvent) { output.invalid({ name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } client function handleInvalid(sourceEvent) { output.invalid({ name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) }
} }
view { view {
<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 {...attrs} class="wire-component wire-component--color-{color} wire-component--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-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}"> <div class="wire-next__field-control" data-icon-position="{iconPosition}">
{#if icon}<span class="{icon} wire-next__field-icon" aria-hidden="true"></span>{/if} {#if icon}<span class="{icon} wire-next__field-icon" aria-hidden="true"></span>{/if}
@@ -62,5 +66,33 @@ size: string = "default"
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if} {#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}
<small class="wire-next__field-error" data-error="{name}">{error}</small> <small class="wire-next__field-error" data-error="{name}">{error}</small>
</div> </div>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next__time-panel {
grid-template-columns: 1fr 1fr;
}
.wire-next__time-options {
display: grid;
max-height: 12rem;
margin-top: 0.4rem;
overflow-y: auto;
gap: 0.2rem;
}
.wire-next__time-done {
align-self: end;
background: var(--wire-field-color) !important;
color: var(--wire-color-primary-contrast, #fff) !important;
}
@media (max-width: 640px) {
.wire-next__time-panel {
grid-template-columns: 1fr;
}
}
} }
} }
+50 -23
View File
@@ -17,71 +17,98 @@ component Timeline {
<section <section
data-ui-component="Timeline" data-ui-component="Timeline"
aria-label='{title}' aria-label='{title}'
class='w-full {class}' class='wire-timeline {class}'
> >
{#if title || description} {#if title || description}
<header class="mb-6"> <header class="wire-timeline__header">
{#if title} {#if title}
<h3 class="text-xl font-bold text-[var(--wire-color-text)]">{title}</h3> <h3 class="wire-timeline__title">{title}</h3>
{/if} {/if}
{#if description} {#if description}
<p class="mt-2 max-w-2xl leading-7 text-[var(--wire-color-text-muted)]">{description}</p> <p class="wire-timeline__description">{description}</p>
{/if} {/if}
</header> </header>
{/if} {/if}
<ol class="relative ml-4 border-l border-[var(--wire-color-border)]"> <ol class="wire-timeline__list">
{#each items as item, index} {#each items as item, index}
<li <li
class="relative pb-8 pl-8 last:pb-0" class="wire-timeline__item"
@click='output.select({ item: item, index: index })' @click='output.select({ item: item, index: index })'
> >
<span <span
class="absolute -left-[1.05rem] top-0 flex size-8 items-center justify-center rounded-full border-4 border-[var(--wire-color-background)] bg-[var(--wire-color-primary)] text-[var(--wire-color-on-primary)] shadow-sm" class="wire-timeline__marker"
class:bg-[var(--wire-color-success)]='item.status === "complete" || item.status === "success"' data-status='{item.status || "default"}'
class:bg-[var(--wire-color-warning)]='item.status === "warning" || item.status === "pending"'
class:bg-[var(--wire-color-danger)]='item.status === "danger" || item.status === "failed"'
> >
<span class='{item.icon || "icon-[lucide--circle]"}' aria-hidden="true"></span> <span class='{item.icon || "icon-[lucide--circle]"}' aria-hidden="true"></span>
</span> </span>
<article <article
class="rounded-2xl border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] p-5 shadow-sm" class="wire-timeline__card"
class:border-transparent='variant === "minimal"' data-variant='{variant}'
class:bg-transparent='variant === "minimal"'
class:p-0='variant === "minimal"'
class:shadow-none='variant === "minimal"'
> >
<div class="flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between"> <div class="wire-timeline__card-header">
<div> <div>
<h4 class="font-bold text-[var(--wire-color-text)]">{item.title || item.label}</h4> <h4 class="wire-timeline__item-title">{item.title || item.label}</h4>
{#if item.subtitle} {#if item.subtitle}
<p class="mt-1 text-sm font-medium text-[var(--wire-color-primary)]">{item.subtitle}</p> <p class="wire-timeline__subtitle">{item.subtitle}</p>
{/if} {/if}
</div> </div>
{#if item.date || item.meta} {#if item.date || item.meta}
<time class="shrink-0 text-sm text-[var(--wire-color-text-muted)]">{item.date || item.meta}</time> <time class="wire-timeline__time">{item.date || item.meta}</time>
{/if} {/if}
</div> </div>
{#if item.description} {#if item.description}
<p class="mt-3 text-sm leading-6 text-[var(--wire-color-text-muted)]">{item.description}</p> <p class="wire-timeline__copy">{item.description}</p>
{/if} {/if}
{#if item.href} {#if item.href}
<a href='{item.href}' class="mt-4 inline-flex items-center gap-2 text-sm font-semibold text-[var(--wire-color-primary)] hover:text-[var(--wire-color-primary-hover)]"> <a href='{item.href}' class="wire-timeline__action">
<span>{item.actionLabel || "View details"}</span> <span>{item.actionLabel || "View details"}</span>
<span class="icon-[lucide--arrow-right] size-4" aria-hidden="true"></span> <span class="icon-[lucide--arrow-right] wire-timeline__action-icon" aria-hidden="true"></span>
</a> </a>
{/if} {/if}
</article> </article>
</li> </li>
{:empty} {:empty}
<li class="pl-8 text-sm text-[var(--wire-color-text-muted)]">No timeline items available.</li> <li class="wire-timeline__empty">No timeline items available.</li>
{/each} {/each}
</ol> </ol>
<slot></slot> <slot></slot>
</section> </section>
} }
style {
.wire-timeline { width: 100%; }
.wire-timeline__header { margin-bottom: 1.5rem; }
.wire-timeline__title { color: var(--wire-color-text); font-size: 1.25rem; font-weight: 700; }
.wire-timeline__description { max-width: 42rem; margin-top: 0.5rem; color: var(--wire-color-text-muted); line-height: 1.75rem; }
.wire-timeline__list { position: relative; margin-left: 1rem; border-left: 1px solid var(--wire-color-border); }
.wire-timeline__item { position: relative; padding: 0 0 2rem 2rem; cursor: pointer; }
.wire-timeline__item:last-child { padding-bottom: 0; }
.wire-timeline__marker {
position: absolute; top: 0; left: -1.05rem; display: flex; width: 2rem; height: 2rem;
align-items: center; justify-content: center; border: 4px solid var(--wire-color-background);
border-radius: 50%; color: var(--wire-color-on-primary); background: var(--wire-color-primary); box-shadow: var(--wire-shadow-1);
}
.wire-timeline__marker:is([data-status="complete"], [data-status="success"]) { background: var(--wire-color-success); }
.wire-timeline__marker:is([data-status="warning"], [data-status="pending"]) { background: var(--wire-color-warning); }
.wire-timeline__marker:is([data-status="danger"], [data-status="failed"]) { background: var(--wire-color-danger); }
.wire-timeline__card { padding: 1.25rem; border: 1px solid var(--wire-color-border); border-radius: calc(var(--wire-radius) * 1.5); background: var(--wire-color-surface-raised); box-shadow: var(--wire-shadow-1); }
.wire-timeline__card[data-variant="minimal"] { padding: 0; border-color: transparent; background: transparent; box-shadow: none; }
.wire-timeline__card-header { display: flex; flex-direction: column; gap: 0.5rem; }
.wire-timeline__item-title { color: var(--wire-color-text); font-weight: 700; }
.wire-timeline__subtitle { margin-top: 0.25rem; color: var(--wire-color-primary); font-size: 0.875rem; font-weight: 500; }
.wire-timeline__time { flex: none; color: var(--wire-color-text-muted); font-size: 0.875rem; }
.wire-timeline__copy { margin-top: 0.75rem; color: var(--wire-color-text-muted); font-size: 0.875rem; line-height: 1.5rem; }
.wire-timeline__action { display: inline-flex; align-items: center; gap: 0.5rem; margin-top: 1rem; color: var(--wire-color-primary); font-size: 0.875rem; font-weight: 600; }
.wire-timeline__action:hover { color: var(--wire-color-primary-hover); }
.wire-timeline__action-icon { width: 1rem; height: 1rem; }
.wire-timeline__empty { padding-left: 2rem; color: var(--wire-color-text-muted); font-size: 0.875rem; }
@media (min-width: 40rem) {
.wire-timeline__card-header { flex-direction: row; align-items: flex-start; justify-content: space-between; }
}
}
} }
-24
View File
@@ -1,24 +0,0 @@
component Toast {
outputs {
dismiss(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
action(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
}
props {
size: string = "default"
color: string = "primary"
title: string = "Toast"
description: string = ""
items: unknown[] = []
variant: string = "default"
class: string = ""
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--toast 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>
}
}
@@ -1,26 +0,0 @@
component ToastNotifications {
outputs {
add(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])
dismiss(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
clear(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
action(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
}
props {
size: string = "default"
color: string = "primary"
title: string = "Toast Notifications"
description: string = ""
items: unknown[] = []
variant: string = "default"
class: string = ""
}
view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--toast-notifications 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>
}
}
+192 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component ToggleCount { component ToggleCount {
outputs { outputs {
change(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) change(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -222,7 +224,7 @@ component ToggleCount {
data-variant="{variant}" data-variant="{variant}"
data-value="{selectedValue}" data-value="{selectedValue}"
data-disabled="{disabled ? 'true' : 'false'}" 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}" class="wire-component wire-component--color-{color} wire-component--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}" /> <input type="hidden" name="{name}" value="{selectedValue}" />
@@ -279,5 +281,194 @@ component ToggleCount {
</div> </div>
{/if} {/if}
</section> </section>
<ComponentBaseStyles hidden />
}
style {
.wire-next__toggle-count-control--start {
justify-content: flex-start;
}
.wire-next__toggle-count-control--center {
justify-content: center;
}
.wire-next__toggle-count-control--end {
justify-content: flex-end;
}
.wire-next--toggle-count {
--wire-toggle-count-accent: var(--wire-component-color);
display: grid;
width: fit-content;
gap: 0.75rem;
color: var(--wire-color-text);
}
.wire-next--toggle-count-full {
width: 100%;
}
.wire-next__toggle-count-control {
display: flex;
}
.wire-next__toggle-count-segmented {
display: inline-flex;
gap: 0.2rem;
padding: 0.2rem;
border-radius: calc(var(--wire-radius-sm) + 0.15rem);
background: var(--wire-color-surface-2);
box-shadow: inset 0 0 0 1px var(--wire-color-border);
}
.wire-next__toggle-count-segmented button {
min-height: 2.35rem;
padding: 0.45rem 0.8rem;
border: 0;
border-radius: var(--wire-radius-sm);
background: transparent;
color: var(--wire-color-muted);
font: inherit;
font-size: 0.78rem;
font-weight: 700;
cursor: pointer;
}
.wire-next__toggle-count-segmented button[aria-pressed="true"] {
background: var(--wire-color-surface);
color: var(--wire-color-text);
box-shadow:
var(--wire-shadow-1),
inset 0 -2px var(--wire-toggle-count-accent);
}
.wire-next__toggle-count-segmented button:focus-visible,
.wire-next__toggle-count-switch:focus-visible {
outline: 2px solid var(--wire-toggle-count-accent);
outline-offset: 2px;
}
.wire-next__toggle-count-segmented button:disabled,
.wire-next__toggle-count-switch:disabled {
cursor: not-allowed;
}
.wire-next__toggle-count-control:has(.wire-next__toggle-count-switch) {
align-items: center;
gap: 0.7rem;
font-size: 0.78rem;
font-weight: 700;
}
.wire-next__toggle-count-control > span {
color: var(--wire-color-muted);
}
.wire-next__toggle-count-control > span[data-selected="true"] {
color: var(--wire-color-text);
}
.wire-next__toggle-count-switch {
position: relative;
width: 2.65rem;
height: 1.45rem;
padding: 0.15rem;
border: 1px solid var(--wire-color-border);
border-radius: 999px;
background: var(--wire-color-surface-2);
cursor: pointer;
transition: background-color var(--wire-motion-fast) var(--wire-ease-standard);
}
.wire-next__toggle-count-switch > span {
display: block;
width: 1rem;
height: 1rem;
border-radius: 50%;
background: var(--wire-color-text);
box-shadow: var(--wire-shadow-1);
transition: transform var(--wire-motion-fast) var(--wire-ease-standard);
}
.wire-next__toggle-count-switch[aria-checked="true"] {
border-color: var(--wire-toggle-count-accent);
background: var(--wire-toggle-count-accent);
}
.wire-next__toggle-count-switch[aria-checked="true"] > span {
background: white;
transform: translateX(1.15rem);
}
.wire-next__toggle-count-items {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
overflow: hidden;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-md);
background: var(--wire-color-surface);
}
.wire-next__toggle-count-items article {
display: grid;
align-content: start;
gap: 0.35rem;
min-width: 0;
padding: 1rem;
}
.wire-next__toggle-count-items article + article {
border-left: 1px solid var(--wire-color-border);
}
.wire-next__toggle-count-items article > span {
color: var(--wire-color-muted);
font-size: 0.75rem;
font-weight: 600;
}
.wire-next__toggle-count-items strong {
display: flex;
align-items: baseline;
gap: 0.2rem;
font-size: 1.5rem;
line-height: 1;
}
.wire-next__toggle-count-items [data-toggle-count-value] {
min-width: 2ch;
font-variant-numeric: tabular-nums;
transition:
color var(--wire-motion-fast) var(--wire-ease-standard),
transform var(--wire-motion-fast) var(--wire-ease-standard);
}
.wire-next__toggle-count-items strong small {
color: inherit;
font-size: 0.65em;
}
.wire-next__toggle-count-items article > small {
color: var(--wire-color-muted);
font-size: 0.68rem;
}
@media (max-width: 36rem) {
.wire-next__toggle-count-control {
justify-content: center;
}
.wire-next__toggle-count-items {
grid-template-columns: 1fr;
}
.wire-next__toggle-count-items article + article {
border-top: 1px solid var(--wire-color-border);
border-left: 0;
}
}
@media (prefers-reduced-motion: reduce) {
.wire-next__toggle-count-items [data-toggle-count-value] {
transition: none;
}
}
} }
} }
+143 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component TogglePassword { component TogglePassword {
outputs { outputs {
input(payload: { name?: string; value: string | number | boolean | null | object; visible: boolean }) input(payload: { name?: string; value: string | number | boolean | null | object; visible: boolean })
@@ -53,7 +57,7 @@ component TogglePassword {
view { view {
<fieldset <fieldset
class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--toggle-password {invalid ? 'wire-next--invalid' : ''} {disabled ? 'wire-next--disabled' : ''} {class}" class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--toggle-password {invalid ? 'wire-next--invalid' : ''} {disabled ? 'wire-next--disabled' : ''} {class}"
data-wrn-toggle-password data-wrn-toggle-password
data-visible="{revealed ? 'true' : 'false'}" data-visible="{revealed ? 'true' : 'false'}"
> >
@@ -152,5 +156,143 @@ component TogglePassword {
data-error="{name}" data-error="{name}"
>{validationMessage}</small> >{validationMessage}</small>
</fieldset> </fieldset>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next--toggle-password {
display: grid;
width: 100%;
min-width: 0;
max-width: none;
box-sizing: border-box;
gap: 0.45rem;
padding: 0;
border: 0;
}
.wire-next--toggle-password > label {
color: var(--wire-color-text);
font-size: 0.75rem;
font-weight: 600;
}
.wire-next__password-fields {
display: grid;
gap: 1rem;
}
.wire-next__password-field {
display: grid;
gap: 0.45rem;
}
.wire-next__password-field > label {
color: var(--wire-color-text);
font-size: 0.82em;
font-weight: 750;
}
.wire-next__password-control {
position: relative;
display: flex;
min-width: 0;
align-items: center;
width: 100%;
}
.wire-next__password-control > input {
width: 100%;
min-width: 0;
min-height: 2.75em;
padding: 0.65em 3em 0.65em 0.8em;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-sm);
outline: 0;
color: var(--wire-color-text);
background: var(--wire-color-bg);
font: inherit;
font-size: 0.8125rem;
transition:
border-color var(--wire-motion-base) var(--wire-ease-standard),
box-shadow var(--wire-motion-base) var(--wire-ease-standard);
}
.wire-next__password-control > input:focus-visible {
border-color: var(--wire-component-color);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--wire-component-color) 18%, transparent);
}
.wire-next__password-toggle {
position: absolute;
top: 50%;
right: 0.45em;
display: grid;
width: 2em;
height: 2em;
padding: 0;
place-items: center;
border: 0;
border-radius: calc(var(--wire-radius-sm) * 0.72);
color: var(--wire-color-muted);
background: transparent;
cursor: pointer;
transform: translateY(-50%);
}
.wire-next__password-toggle:hover,
.wire-next__password-toggle:focus-visible {
color: var(--wire-component-color);
background: color-mix(in srgb, var(--wire-component-color) 10%, transparent);
outline: 0;
}
.wire-next__password-icon {
display: block;
width: 1.05em;
height: 1.05em;
background: currentColor;
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
}
.wire-next__password-icon--show {
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.06 12.35a1 1 0 0 1 0-.7C3.7 7.6 7.64 5 12 5c4.36 0 8.3 2.6 9.94 6.65a1 1 0 0 1 0 .7C20.3 16.4 16.36 19 12 19c-4.36 0-8.3-2.6-9.94-6.65Z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E");
}
.wire-next__password-toggle[aria-pressed="true"]::after {
position: absolute;
width: 1.25em;
height: 0.12em;
border-radius: 999px;
background: currentColor;
content: "";
transform: rotate(45deg);
box-shadow: 0 0 0 1px var(--wire-color-bg);
}
.wire-next__password-checkbox {
display: inline-flex;
width: fit-content;
align-items: center;
gap: 0.55rem;
color: var(--wire-color-muted);
font-size: 0.78em;
cursor: pointer;
}
.wire-next__password-checkbox > input {
width: 1rem;
height: 1rem;
margin: 0;
accent-color: var(--wire-component-color);
}
.wire-next--toggle-password > small {
color: var(--wire-color-muted);
font-size: 0.72em;
}
} }
} }
+88 -11
View File
@@ -1,26 +1,103 @@
component TreeView { component TreeView {
outputs { outputs {
select(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) select(payload: { item: object; value: string; sourceEvent?: Event })
toggle(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) toggle(payload: { item: object; value: string; expanded: boolean; sourceEvent?: Event })
expand(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) expand(payload: { item: object; value: string; sourceEvent?: Event })
collapse(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) collapse(payload: { item: object; value: string; sourceEvent?: Event })
} }
props { props {
size: string = "default"
color: string = "primary"
title: string = "Tree View" title: string = "Tree View"
description: string = "" description: string = ""
items: unknown[] = [] items: unknown[] = []
variant: string = "default" valueKey: string = "value"
labelKey: string = "label"
defaultExpanded: unknown[] = []
selected: string = ""
size: string = "default"
color: string = "primary"
class: string = "" class: string = ""
} }
state expandedValues = defaultExpanded
state selectedValue = selected
functions {
shared function nodeValue(item, index, parent) { return String(item[valueKey] || item.id || parent + index) }
shared function isExpanded(value) { return expandedValues.includes(value) }
client function toggleNode(item, value, sourceEvent, next, expanded) {
next = expandedValues.slice()
expanded = !next.includes(value)
if (expanded) {
next.push(value)
} else {
next = next.filter(function (entry) { return entry !== value })
}
expandedValues = next
output.toggle({ item: item, value: value, expanded: expanded, sourceEvent: sourceEvent })
if (expanded) {
output.expand({ item: item, value: value, sourceEvent: sourceEvent })
} else {
output.collapse({ item: item, value: value, sourceEvent: sourceEvent })
}
}
client function selectNode(item, value, sourceEvent) {
selectedValue = value
output.select({ item: item, value: value, sourceEvent: sourceEvent })
}
}
view { view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--tree-view wire-next--variant-{variant} {class}"> <section {...attrs} data-ui-component="TreeView" class='wire-tree-view {class}'>
{#if title}<strong>{title}</strong>{/if} {#if title}<strong class="wire-tree-view__title">{title}</strong>{/if}
{#if description}<p>{description}</p>{/if} {#if description}<p class="wire-tree-view__description">{description}</p>{/if}
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if} <div class="wire-tree-view__tree" role="tree" aria-label='{title}' data-wrn-roving="vertical">
{#each items as item, index}
<div class="wire-tree-view__branch" role="none">
<div class="wire-tree-view__row" role="treeitem" aria-level="1" aria-expanded='{item.children && item.children.length ? isExpanded(nodeValue(item, index, "root-")) : ""}' aria-selected='{selectedValue === nodeValue(item, index, "root-") ? "true" : "false"}'>
{#if item.children && item.children.length}
<button type="button" class="wire-tree-view__toggle" aria-label='{isExpanded(nodeValue(item, index, "root-")) ? "Collapse " + item[labelKey] : "Expand " + item[labelKey]}' @click='toggleNode(item, nodeValue(item, index, "root-"), event)'><span class="icon-[lucide--chevron-right]" aria-hidden="true"></span></button>
{:else}<span class="wire-tree-view__toggle" aria-hidden="true"></span>{/if}
<button type="button" class="wire-tree-view__node" data-wrn-roving-item @click='selectNode(item, nodeValue(item, index, "root-"), event)'>
{#if item.icon}<span class='{item.icon}' aria-hidden="true"></span>{/if}<span>{item[labelKey]}</span>
</button>
</div>
{#if item.children && item.children.length}
<div class="wire-tree-view__group" role="group" data-show='isExpanded(nodeValue(item, index, "root-"))'>
{#each item.children as child, childIndex}
<div class="wire-tree-view__row" role="treeitem" aria-level="2" aria-selected='{selectedValue === nodeValue(child, childIndex, nodeValue(item, index, "root-") + "-") ? "true" : "false"}'>
<span class="wire-tree-view__toggle" aria-hidden="true"></span>
<button type="button" class="wire-tree-view__node" data-wrn-roving-item @click='selectNode(child, nodeValue(child, childIndex, nodeValue(item, index, "root-") + "-"), event)'>
{#if child.icon}<span class='{child.icon}' aria-hidden="true"></span>{/if}<span>{child[labelKey]}</span>
</button>
</div>
{/each}
</div>
{/if}
</div>
{:empty}<p class="wire-tree-view__empty">No tree items available.</p>{/each}
</div>
<slot /> <slot />
</section> </section>
} }
style {
.wire-tree-view { display: grid; gap: 0.5rem; color: var(--wire-color-text); }
.wire-tree-view__title { font-size: 0.95rem; }
.wire-tree-view__description, .wire-tree-view__empty { margin: 0; color: var(--wire-color-muted); font-size: 0.8rem; }
.wire-tree-view__tree { display: grid; gap: 0.15rem; padding: 0.4rem; border: 1px solid var(--wire-color-border); border-radius: var(--wire-radius); background: var(--wire-color-surface); }
.wire-tree-view__row { display: flex; min-width: 0; align-items: center; gap: 0.2rem; border-radius: var(--wire-radius-sm); }
.wire-tree-view__row[aria-selected="true"] { background: var(--wire-color-primary-soft); }
.wire-tree-view__toggle { display: inline-grid; width: 1.8rem; height: 1.8rem; flex: none; padding: 0; place-items: center; border: 0; border-radius: 0.35rem; color: var(--wire-color-muted); background: transparent; }
button.wire-tree-view__toggle { cursor: pointer; }
.wire-tree-view__toggle > span { width: 0.9rem; height: 0.9rem; transition: transform var(--wire-motion-fast); }
.wire-tree-view__row[aria-expanded="true"] > .wire-tree-view__toggle > span { transform: rotate(90deg); }
.wire-tree-view__node { display: flex; min-width: 0; flex: 1; align-items: center; gap: 0.45rem; padding: 0.45rem 0.5rem; border: 0; border-radius: var(--wire-radius-sm); color: inherit; background: transparent; font: inherit; text-align: left; cursor: pointer; }
.wire-tree-view__node:hover, button.wire-tree-view__toggle:hover { background: var(--wire-color-surface-2); }
.wire-tree-view__node:focus-visible, button.wire-tree-view__toggle:focus-visible { outline: 2px solid var(--wire-color-focus); outline-offset: -2px; }
.wire-tree-view__node > [class*="icon-"] { width: 1rem; height: 1rem; flex: none; color: var(--wire-color-primary); }
.wire-tree-view__group { display: grid; margin-left: 1.8rem; padding-left: 0.45rem; border-left: 1px solid var(--wire-color-border); }
}
} }
+19 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component WysiwygEditor { component WysiwygEditor {
outputs { outputs {
input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -16,11 +18,27 @@ component WysiwygEditor {
class: string = "" class: string = ""
} }
view { view {
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--wysiwyg-editor wire-next--variant-{variant} {class}"> <section class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--wysiwyg-editor wire-next--variant-{variant} {class}">
{#if title}<strong>{title}</strong>{/if} {#if title}<strong>{title}</strong>{/if}
{#if description}<p>{description}</p>{/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} {#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
<slot /> <slot />
</section> </section>
<ComponentBaseStyles hidden />
}
style {
.wire-next--wysiwyg-editor {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius);
color: var(--wire-color-text);
background: var(--wire-color-surface);
}
.wire-next--wysiwyg-editor > p { margin: 0; color: var(--wire-color-muted); }
.wire-next--wysiwyg-editor > .wire-next__items { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.wire-next--wysiwyg-editor > .wire-next__items > span { padding: 0.35rem 0.6rem; border-radius: var(--wire-radius-sm); background: var(--wire-color-surface-2); }
} }
} }
+251 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Alert { component Alert {
outputs { outputs {
dismiss(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) dismiss(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
@@ -76,7 +78,7 @@ component Alert {
aria-hidden="{visible ? 'false' : 'true'}" aria-hidden="{visible ? 'false' : 'true'}"
role="{role}" role="{role}"
aria-live="{live}" 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}" class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--alert wire-next--alert-{variant} {compact ? 'wire-next--alert-compact' : ''} {class}"
> >
{#if showIcon} {#if showIcon}
<span class="wire-next__alert-icon" aria-hidden="true"> <span class="wire-next__alert-icon" aria-hidden="true">
@@ -142,5 +144,253 @@ component Alert {
</button> </button>
{/if} {/if}
</section> </section>
<ComponentBaseStyles hidden />
}
style {
.wire-next--alert-soft {
border-color: color-mix(in srgb, var(--wire-alert-color) 45%, var(--wire-color-border));
background: var(--wire-alert-soft);
}
.wire-next--alert-soft .wire-next__alert-title,
.wire-next--alert-soft .wire-next__alert-icon,
.wire-next--alert-soft .wire-next__alert-actions a {
color: var(--wire-alert-color);
}
.wire-next--alert-solid {
border-color: var(--wire-alert-color);
background: var(--wire-alert-color);
color: white;
}
.wire-next--alert.wire-next--alert-solid
:is(
.wire-next__alert-title,
.wire-next__alert-body > p,
.wire-next__alert-body li,
.wire-next__alert-actions a,
.wire-next__alert-icon
) {
color: currentColor;
}
.wire-next--alert-solid[data-color="light"] {
color: #18181b;
}
.wire-next--alert-solid[data-color="warning"] {
color: #18181b;
}
.wire-next--alert-bordered {
border-color: var(--wire-alert-color);
background: var(--wire-color-surface);
}
.wire-next--alert-bordered .wire-next__alert-title,
.wire-next--alert-bordered .wire-next__alert-icon,
.wire-next--alert-bordered .wire-next__alert-actions a {
color: var(--wire-alert-color);
}
.wire-next--alert-accent {
border-color: color-mix(in srgb, var(--wire-alert-color) 35%, var(--wire-color-border));
border-left: 4px solid var(--wire-alert-color);
background: var(--wire-alert-soft);
}
.wire-next--alert-accent .wire-next__alert-title,
.wire-next--alert-accent .wire-next__alert-icon,
.wire-next--alert-accent .wire-next__alert-actions a {
color: var(--wire-alert-color);
}
.wire-next--alert {
--wire-alert-color: var(--wire-component-color);
--wire-alert-soft: color-mix(in srgb, var(--wire-alert-color) 16%, var(--wire-color-surface));
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
gap: 0.8rem;
width: 100%;
padding: 1rem;
border: 1px solid transparent;
border-radius: var(--wire-radius, 0.75rem);
color: var(--wire-color-text);
}
.wire-next--alert[data-radius="none"] {
border-radius: 0;
}
.wire-next--alert[data-radius="sm"] {
border-radius: var(--wire-radius-sm, 0.375rem);
}
.wire-next--alert[data-radius="lg"] {
border-radius: calc(var(--wire-radius, 0.75rem) * 1.35);
}
.wire-next--alert[data-radius="xl"] {
border-radius: calc(var(--wire-radius, 0.75rem) * 1.75);
}
.wire-next--alert[data-shadow="none"] {
box-shadow: none;
}
.wire-next--alert[data-shadow="sm"] {
box-shadow: 0 6px 16px color-mix(in srgb, #000 14%, transparent);
}
.wire-next--alert[data-shadow="md"] {
box-shadow:
0 2px 6px color-mix(in srgb, #000 10%, transparent),
0 12px 28px color-mix(in srgb, #000 18%, transparent);
}
.wire-next--alert[data-shadow="lg"] {
box-shadow:
0 4px 10px color-mix(in srgb, #000 12%, transparent),
0 20px 48px color-mix(in srgb, #000 24%, transparent);
}
.wire-next--alert[data-color="secondary"] {
--wire-alert-color: #737373;
}
.wire-next--alert[data-color="success"] {
--wire-alert-color: #0f9f8f;
}
.wire-next--alert[data-color="danger"] {
--wire-alert-color: #dc3545;
}
.wire-next--alert[data-color="warning"] {
--wire-alert-color: #eab308;
}
.wire-next--alert[data-color="info"] {
--wire-alert-color: #2563eb;
}
.wire-next--alert[data-color="dark"] {
--wire-alert-color: #27272a;
}
.wire-next--alert[data-color="light"] {
--wire-alert-color: #f4f4f5;
}
.wire-next--alert-compact {
padding: 0.75rem 0.9rem;
}
.wire-next--alert-compact:not(:has(.wire-next__alert-icon)):not(:has(.wire-next__alert-dismiss)) {
grid-template-columns: minmax(0, 1fr);
}
.wire-next--alert-compact .wire-next__alert-body {
display: block;
}
.wire-next--alert-compact .wire-next__alert-title {
margin-right: 0.25rem;
}
.wire-next--alert-compact .wire-next__alert-body > p {
display: inline;
}
.wire-next__alert-icon {
display: inline-grid;
width: 1.25rem;
height: 1.25rem;
place-items: center;
margin-top: 0.05rem;
color: var(--wire-alert-color);
}
.wire-next__alert-icon > span {
width: 1rem;
height: 1rem;
}
.wire-next__alert-body {
display: grid;
min-width: 0;
gap: 0.35rem;
}
.wire-next__alert-title {
font-size: 0.88rem;
line-height: 1.45;
}
.wire-next__alert-body > p,
.wire-next__alert-body li {
color: inherit;
font-size: 0.8rem;
line-height: 1.55;
}
.wire-next__alert-body > ul {
display: grid;
gap: 0.25rem;
margin: 0.15rem 0 0;
padding-left: 1.25rem;
}
.wire-next__alert-actions {
display: flex;
flex-wrap: wrap;
gap: 0.5rem 1rem;
margin-top: 0.35rem;
}
.wire-next__alert-actions a {
color: var(--wire-alert-color);
font-size: 0.78rem;
font-weight: 700;
text-decoration: none;
}
.wire-next__alert-actions a:hover {
text-decoration: underline;
}
.wire-next__alert-actions a[data-variant="action"] {
padding: 0.35rem 0.6rem;
border-radius: var(--wire-radius-sm);
background: var(--wire-alert-color);
color: white;
text-decoration: none;
}
.wire-next__alert-dismiss {
display: inline-grid;
width: 1.75rem;
height: 1.75rem;
place-items: center;
padding: 0;
border: 0;
border-radius: var(--wire-radius-sm);
background: transparent;
color: currentColor;
cursor: pointer;
}
.wire-next__alert-dismiss:hover {
background: color-mix(in srgb, currentColor 10%, transparent);
}
.wire-next__alert-dismiss:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}
@media (max-width: 36rem) {
.wire-next--alert {
grid-template-columns: auto minmax(0, 1fr);
}
.wire-next__alert-dismiss {
grid-column: 2;
grid-row: 1;
justify-self: end;
}
}
} }
} }
+265 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Avatar { component Avatar {
outputs { outputs {
load(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) load(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
@@ -32,7 +34,7 @@ src: string = ""
view { view {
<span <span
{...attrs} {...attrs}
class="wire-next wire-next--avatar {description ? 'wire-next--avatar-media' : ''} {class}" class="wire-component wire-next--avatar {description ? 'wire-next--avatar-media' : ''} {class}"
data-wrn-avatar data-wrn-avatar
> >
<span <span
@@ -86,5 +88,267 @@ src: string = ""
</span> </span>
{/if} {/if}
</span> </span>
<ComponentBaseStyles hidden />
}
style {
/* --- Avatar -------------------------------------------------------------- */
.wire-next--avatar {
display: inline-flex;
width: fit-content;
max-width: 100%;
align-items: center;
}
.wire-next--avatar-media {
gap: 0.8rem;
}
.wire-next__avatar-wrap {
--wire-avatar-size: 3rem;
--wire-avatar-color: var(--wire-color-primary);
position: relative;
display: inline-grid;
width: var(--wire-avatar-size);
height: var(--wire-avatar-size);
flex: none;
place-items: center;
border-radius: 999px;
outline: none;
}
.wire-next__avatar-wrap[data-size="xs"] {
--wire-avatar-size: 1.75rem;
}
.wire-next__avatar-wrap[data-size="sm"] {
--wire-avatar-size: 2.25rem;
}
.wire-next__avatar-wrap[data-size="md"],
.wire-next__avatar-wrap[data-size="default"] {
--wire-avatar-size: 3rem;
}
.wire-next__avatar-wrap[data-size="lg"] {
--wire-avatar-size: 4rem;
}
.wire-next__avatar-wrap[data-size="xl"] {
--wire-avatar-size: 5rem;
}
.wire-next__avatar-wrap[data-color="secondary"] {
--wire-avatar-color: #737373;
}
.wire-next__avatar-wrap[data-color="success"] {
--wire-avatar-color: var(--wire-color-success);
}
.wire-next__avatar-wrap[data-color="info"] {
--wire-avatar-color: var(--wire-color-info);
}
.wire-next__avatar-wrap[data-color="danger"] {
--wire-avatar-color: var(--wire-color-danger);
}
.wire-next__avatar-wrap[data-color="warning"] {
--wire-avatar-color: var(--wire-color-warning);
}
.wire-next__avatar-wrap[data-color="light"] {
--wire-avatar-color: #f4f4f5;
}
.wire-next__avatar-wrap[data-color="dark"] {
--wire-avatar-color: #27272a;
}
.wire-next__avatar {
display: grid;
width: 100%;
height: 100%;
overflow: hidden;
place-items: center;
color: white;
border: 1px solid color-mix(in srgb, var(--wire-avatar-color) 58%, var(--wire-color-border));
border-radius: inherit;
background: var(--wire-avatar-color);
box-shadow:
0 0 0 2px var(--wire-color-bg),
0 5px 14px rgb(0 0 0 / 0.16);
}
.wire-next__avatar-wrap[data-shape="rounded"] {
border-radius: calc(var(--wire-radius-sm, 0.5rem) * 0.72);
}
.wire-next__avatar-wrap[data-shape="square"] {
border-radius: 0;
}
.wire-next__avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.wire-next__avatar-initials {
font-size: calc(var(--wire-avatar-size) * 0.32);
font-weight: 750;
line-height: 1;
letter-spacing: -0.02em;
}
.wire-next__avatar-placeholder {
width: 54%;
height: 54%;
color: currentColor;
opacity: 0.72;
}
.wire-next__avatar-wrap[data-variant="soft"] .wire-next__avatar {
color: var(--wire-avatar-color);
border-color: transparent;
background: color-mix(in srgb, var(--wire-avatar-color) 15%, var(--wire-color-surface));
box-shadow: none;
}
.wire-next__avatar-wrap[data-variant="outline"] .wire-next__avatar {
color: var(--wire-avatar-color);
border-color: var(--wire-avatar-color);
background: transparent;
box-shadow: none;
}
.wire-next__avatar-wrap[data-variant="white"] .wire-next__avatar {
color: var(--wire-color-text);
border-color: var(--wire-color-border);
background: var(--wire-color-surface);
box-shadow: 0 4px 12px rgb(0 0 0 / 0.12);
}
.wire-next__avatar-status {
position: absolute;
right: -0.04rem;
bottom: -0.04rem;
z-index: 2;
width: max(0.58rem, calc(var(--wire-avatar-size) * 0.24));
height: max(0.58rem, calc(var(--wire-avatar-size) * 0.24));
border: 2px solid var(--wire-color-bg);
border-radius: 999px;
background: var(--wire-color-muted);
}
.wire-next__avatar-wrap[data-status-position="top"] .wire-next__avatar-status {
top: -0.04rem;
bottom: auto;
}
.wire-next__avatar-status[data-status="online"],
.wire-next__avatar-status[data-status="success"] {
background: #14cba8;
}
.wire-next__avatar-status[data-status="busy"],
.wire-next__avatar-status[data-status="danger"] {
background: #fb5b68;
}
.wire-next__avatar-status[data-status="away"],
.wire-next__avatar-status[data-status="warning"] {
background: #ffc400;
}
.wire-next__avatar-badge {
position: absolute;
right: -0.25rem;
bottom: -0.25rem;
z-index: 3;
display: grid;
width: max(1rem, calc(var(--wire-avatar-size) * 0.42));
height: max(1rem, calc(var(--wire-avatar-size) * 0.42));
place-items: center;
color: white;
border: 2px solid var(--wire-color-bg);
border-radius: 999px;
background: #27272a;
box-shadow: 0 4px 10px rgb(0 0 0 / 0.22);
}
.wire-next__avatar-badge > span {
width: 62%;
height: 62%;
}
.wire-next__avatar-badge--text {
font-size: calc(var(--wire-avatar-size) * 0.18);
font-weight: 800;
}
.wire-next__avatar-tooltip {
position: absolute;
left: 50%;
bottom: calc(100% + 0.65rem);
z-index: 20;
width: max-content;
max-width: 15rem;
padding: 0.4rem 0.6rem;
color: var(--wire-color-bg);
border-radius: 0.4rem;
background: var(--wire-color-text);
box-shadow: 0 8px 22px rgb(0 0 0 / 0.2);
font-size: 0.75rem;
font-weight: 650;
line-height: 1.25;
pointer-events: none;
opacity: 0;
transform: translate(-50%, 0.25rem);
transition:
opacity var(--wire-motion-fast) var(--wire-ease-standard),
transform var(--wire-motion-fast) var(--wire-ease-standard);
}
.wire-next__avatar-tooltip::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
border: 0.3rem solid transparent;
border-top-color: var(--wire-color-text);
transform: translateX(-50%);
}
.wire-next__avatar-wrap:hover .wire-next__avatar-tooltip,
.wire-next__avatar-wrap:focus-visible .wire-next__avatar-tooltip {
opacity: 1;
transform: translate(-50%, 0);
}
.wire-next__avatar-wrap:focus-visible {
outline: 2px solid var(--wire-avatar-color);
outline-offset: 4px;
}
.wire-next__avatar-copy {
display: grid;
min-width: 0;
gap: 0.15rem;
}
.wire-next__avatar-copy strong {
color: var(--wire-color-text);
font-size: 0.9rem;
}
.wire-next__avatar-copy > span {
overflow: hidden;
color: var(--wire-color-muted);
font-size: 0.78rem;
text-overflow: ellipsis;
white-space: nowrap;
}
} }
} }
+252 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Badge { component Badge {
outputs { outputs {
dismiss(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) dismiss(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
@@ -48,7 +50,7 @@ component Badge {
view { view {
<span <span
{...attrs} {...attrs}
class="wire-next wire-next--badge-root {anchorLabel || anchorIcon ? 'wire-next--badge-anchored' : ''} {class}" class="wire-component wire-next--badge-root {anchorLabel || anchorIcon ? 'wire-next--badge-anchored' : ''} {class}"
data-wrn-badge data-wrn-badge
data-placement="{placement}" data-placement="{placement}"
data-show="visible" data-show="visible"
@@ -99,5 +101,254 @@ component Badge {
{/if} {/if}
</span> </span>
</span> </span>
<ComponentBaseStyles hidden />
}
style {
@keyframes wire-badge-ping {
75%,
100% {
opacity: 0;
transform: scale(1.45);
}
}
/* --- Badge --------------------------------------------------------------- */
.wire-next--badge-root {
position: relative;
display: inline-flex;
width: fit-content;
max-width: 100%;
vertical-align: middle;
}
.wire-next__badge {
--wire-badge-color: var(--wire-color-primary);
position: relative;
isolation: isolate;
display: inline-flex;
min-width: 0;
min-height: 1.65rem;
align-items: center;
justify-content: center;
gap: 0.35rem;
max-width: var(--wire-badge-max-width);
padding: 0.25rem 0.6rem;
color: white;
border: 1px solid var(--wire-badge-color);
border-radius: 999px;
background: var(--wire-badge-color);
box-shadow: 0 4px 12px color-mix(in srgb, var(--wire-badge-color) 18%, transparent);
font-size: 0.75rem;
font-weight: 750;
line-height: 1;
white-space: nowrap;
}
.wire-next__badge[data-size="xs"] {
min-height: 1.25rem;
padding: 0.15rem 0.4rem;
font-size: 0.625rem;
}
.wire-next__badge[data-size="sm"] {
min-height: 1.45rem;
padding: 0.2rem 0.5rem;
font-size: 0.6875rem;
}
.wire-next__badge[data-size="lg"] {
min-height: 2rem;
padding: 0.35rem 0.75rem;
font-size: 0.825rem;
}
.wire-next__badge[data-color="secondary"] {
--wire-badge-color: #737373;
}
.wire-next__badge[data-color="success"] {
--wire-badge-color: #0f9f8f;
}
.wire-next__badge[data-color="info"] {
--wire-badge-color: #2563eb;
}
.wire-next__badge[data-color="danger"] {
--wire-badge-color: #ef3340;
}
.wire-next__badge[data-color="warning"] {
--wire-badge-color: #eab308;
}
.wire-next__badge[data-color="dark"] {
--wire-badge-color: #27272a;
}
.wire-next__badge[data-color="light"] {
--wire-badge-color: #f4f4f5;
}
.wire-next__badge[data-color="warning"][data-variant="solid"],
.wire-next__badge[data-color="light"][data-variant="solid"] {
color: #18181b;
}
.wire-next__badge[data-variant="soft"] {
color: var(--wire-badge-color);
border-color: transparent;
background: color-mix(in srgb, var(--wire-badge-color) 15%, var(--wire-color-surface));
box-shadow: none;
}
.wire-next__badge[data-variant="outline"] {
color: var(--wire-badge-color);
background: transparent;
box-shadow: none;
}
.wire-next__badge[data-variant="white"] {
color: var(--wire-color-text);
border-color: var(--wire-color-border);
background: var(--wire-color-surface);
box-shadow: 0 4px 12px rgb(0 0 0 / 0.12);
}
.wire-next__badge[data-shape="rounded"] {
border-radius: 0.4rem;
}
.wire-next__badge[data-shape="square"] {
border-radius: 0;
}
.wire-next__badge-label {
min-width: 0;
}
.wire-next__badge-label--truncate {
overflow: hidden;
text-overflow: ellipsis;
}
.wire-next__badge-dot {
width: 0.42rem;
height: 0.42rem;
flex: none;
border-radius: 999px;
background: currentColor;
}
.wire-next__badge:has(.wire-next__badge-dot):not(:has(.wire-next__badge-label)) {
width: 0.7rem;
min-width: 0.7rem;
height: 0.7rem;
min-height: 0.7rem;
padding: 0;
border: 2px solid var(--wire-color-bg);
}
.wire-next__badge:has(.wire-next__badge-dot):not(:has(.wire-next__badge-label))
.wire-next__badge-dot {
width: 100%;
height: 100%;
}
.wire-next__badge-icon {
width: 0.9rem;
height: 0.9rem;
flex: none;
}
.wire-next__badge-avatar {
width: 1.25rem;
height: 1.25rem;
margin-left: -0.35rem;
object-fit: cover;
border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
border-radius: 999px;
}
.wire-next__badge-dismiss {
display: grid;
width: 1.15rem;
height: 1.15rem;
margin-right: -0.3rem;
padding: 0;
place-items: center;
color: currentColor;
border: 0;
border-radius: 999px;
background: color-mix(in srgb, currentColor 12%, transparent);
cursor: pointer;
}
.wire-next__badge-dismiss:hover {
background: color-mix(in srgb, currentColor 22%, transparent);
}
.wire-next__badge-dismiss:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}
.wire-next__badge-dismiss span {
width: 0.75rem;
height: 0.75rem;
}
.wire-next__badge-anchor {
display: inline-flex;
min-height: 2.75rem;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.65rem 0.9rem;
color: var(--wire-color-text);
border: 1px solid var(--wire-color-border);
border-radius: 0.5rem;
background: var(--wire-color-surface);
font: inherit;
font-size: 0.875rem;
font-weight: 700;
}
.wire-next__badge-anchor > [class*="icon-"] {
width: 1rem;
height: 1rem;
}
.wire-next--badge-anchored[data-placement="inline"] {
align-items: center;
}
.wire-next--badge-anchored[data-placement="inline"] .wire-next__badge {
margin-left: -0.55rem;
}
.wire-next--badge-anchored[data-placement="top-right"] .wire-next__badge {
position: absolute;
top: -0.55rem;
right: -0.75rem;
z-index: 2;
}
.wire-next__badge-ping {
position: absolute;
z-index: -1;
inset: -0.25rem;
border-radius: inherit;
background: var(--wire-badge-color);
opacity: 0.5;
animation: wire-badge-ping 1.4s cubic-bezier(0, 0, 0.2, 1) infinite;
}
@media (prefers-reduced-motion: reduce) {
.wire-next__badge-ping {
animation: none;
}
}
} }
} }
+300
View File
@@ -164,4 +164,304 @@ label: string = "Button"
{/if} {/if}
</span> </span>
} }
style {
.wire-spinner {
display: inline-block;
width: 1.15rem;
height: 1.15rem;
border: 2px solid var(--wire-color-border);
border-top-color: var(--wire-color-primary);
border-radius: 999px;
animation: wire-spin 0.7s linear infinite;
}
.wire-spinner--inline {
width: 1rem;
height: 1rem;
}
@keyframes wire-spin {
to {
transform: rotate(360deg);
}
}
/* --- Button --------------------------------------------------------------- */
.wire-btn {
position: relative;
--wire-btn-color: var(--wire-color-primary);
--wire-btn-contrast: var(--wire-color-primary-contrast);
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
font: inherit;
font-size: 0.875rem;
font-weight: 600;
line-height: 1;
border: 1px solid transparent;
border-radius: var(--wire-radius-sm);
padding: 0 0.75rem;
cursor: pointer;
text-decoration: none;
min-height: 2rem;
transition:
color var(--wire-motion-base) var(--wire-ease-standard),
border-color var(--wire-motion-base) var(--wire-ease-standard),
background var(--wire-motion-base) var(--wire-ease-standard),
box-shadow var(--wire-motion-base) var(--wire-ease-standard),
transform var(--wire-motion-base) var(--wire-ease-emphasized);
}
.wire-btn:active {
transform: scale(0.98);
}
.wire-btn:focus-visible {
outline: 2px solid var(--wire-color-primary);
outline-offset: 2px;
}
.wire-btn--color-primary {
--wire-btn-color: var(--wire-color-primary);
--wire-btn-contrast: var(--wire-color-primary-contrast);
}
.wire-btn--color-secondary {
--wire-btn-color: var(--wire-color-muted);
--wire-btn-contrast: var(--wire-color-bg);
}
.wire-btn--color-success {
--wire-btn-color: var(--wire-color-success);
--wire-btn-contrast: var(--wire-color-primary-contrast);
}
.wire-btn--color-warning {
--wire-btn-color: var(--wire-color-warning);
--wire-btn-contrast: var(--wire-color-bg);
}
.wire-btn--color-danger {
--wire-btn-color: var(--wire-color-danger);
--wire-btn-contrast: var(--wire-color-primary-contrast);
}
.wire-btn--color-info {
--wire-btn-color: var(--wire-color-info);
--wire-btn-contrast: var(--wire-color-primary-contrast);
}
.wire-btn--variant-default,
.wire-btn--variant-solid,
.wire-btn--default,
.wire-btn--solid,
.wire-btn--primary {
color: var(--wire-btn-contrast);
background: var(--wire-btn-color);
box-shadow:
0 1px 2px color-mix(in srgb, black 20%, transparent),
0 0 0 1px color-mix(in srgb, var(--wire-btn-color) 72%, transparent);
}
.wire-btn--variant-default:hover,
.wire-btn--variant-solid:hover,
.wire-btn--default:hover,
.wire-btn--solid:hover,
.wire-btn--primary:hover {
background: color-mix(in srgb, var(--wire-btn-color) 84%, black);
transform: translateY(-1px);
box-shadow:
0 0.35rem 0.9rem color-mix(in srgb, var(--wire-btn-color) 20%, transparent),
0 0 0 1px color-mix(in srgb, var(--wire-btn-color) 82%, transparent);
}
.wire-btn--variant-outline,
.wire-btn--outline {
color: var(--wire-btn-color);
background: transparent;
border-color: color-mix(in srgb, var(--wire-btn-color) 55%, var(--wire-color-border));
}
.wire-btn--variant-outline:hover,
.wire-btn--outline:hover {
background: color-mix(in srgb, var(--wire-btn-color) 10%, transparent);
border-color: var(--wire-btn-color);
}
.wire-btn--variant-destructive,
.wire-btn--danger,
.wire-btn--destructive {
color: var(--wire-btn-color);
background: color-mix(in srgb, var(--wire-btn-color) 12%, transparent);
border-color: color-mix(in srgb, var(--wire-btn-color) 28%, transparent);
}
.wire-btn--danger,
.wire-btn--destructive {
--wire-btn-color: var(--wire-color-danger);
}
.wire-btn--variant-destructive:hover,
.wire-btn--danger:hover,
.wire-btn--destructive:hover {
background: color-mix(in srgb, var(--wire-btn-color) 20%, transparent);
}
.wire-btn--variant-ghost,
.wire-btn--ghost {
background: transparent;
color: var(--wire-btn-color);
}
.wire-btn--variant-ghost:hover,
.wire-btn--ghost:hover {
background: color-mix(in srgb, var(--wire-btn-color) 10%, transparent);
}
.wire-btn--variant-secondary,
.wire-btn--secondary {
color: var(--wire-color-text);
background: color-mix(in srgb, var(--wire-btn-color) 10%, var(--wire-color-surface));
border-color: color-mix(in srgb, var(--wire-btn-color) 24%, var(--wire-color-border));
box-shadow: var(--wire-shadow-1);
}
.wire-btn--variant-secondary:hover,
.wire-btn--secondary:hover {
color: var(--wire-btn-color);
border-color: color-mix(in srgb, var(--wire-btn-color) 55%, var(--wire-color-border));
background: color-mix(in srgb, var(--wire-btn-color) 15%, var(--wire-color-surface));
transform: translateY(-2px);
}
.wire-btn--variant-link,
.wire-btn--link {
min-height: auto;
padding: 0;
color: var(--wire-btn-color);
background: transparent;
border-color: transparent;
border-radius: 0;
text-underline-offset: 0.22em;
}
.wire-btn--variant-link:hover,
.wire-btn--link:hover {
text-decoration: underline;
}
.wire-btn:disabled,
.wire-btn[aria-busy="true"] {
cursor: not-allowed;
opacity: 0.58;
transform: none;
box-shadow: none;
}
.wire-btn--size-xs,
.wire-btn--xs {
min-height: 1.5rem;
padding-inline: 0.5rem;
gap: 0.25rem;
font-size: 0.75rem;
}
.wire-btn--size-sm,
.wire-btn--sm {
min-height: 2.125rem;
padding-inline: 0.625rem;
gap: 0.25rem;
font-size: 0.8rem;
}
.wire-btn--size-default,
.wire-btn--md {
min-height: 2.5rem;
padding-inline: 0.75rem;
font-size: 0.875rem;
}
.wire-btn--size-lg,
.wire-btn--lg {
min-height: 2.75rem;
padding-inline: 0.875rem;
font-size: 0.925rem;
}
.wire-btn--size-icon,
.wire-btn--size-icon-xs,
.wire-btn--size-icon-sm,
.wire-btn--size-icon-lg,
.wire-btn--icon,
.wire-btn--icon-xs,
.wire-btn--icon-sm,
.wire-btn--icon-lg {
flex: none;
padding: 0;
}
.wire-btn--size-icon,
.wire-btn--icon {
width: 2rem;
height: 2rem;
}
.wire-btn--size-icon-xs,
.wire-btn--icon-xs {
width: 1.5rem;
min-height: 1.5rem;
}
.wire-btn--size-icon-sm,
.wire-btn--icon-sm {
width: 1.75rem;
min-height: 1.75rem;
}
.wire-btn--size-icon-lg,
.wire-btn--icon-lg {
width: 2.25rem;
min-height: 2.25rem;
}
.wire-btn__icon {
width: 1rem;
height: 1rem;
flex: none;
}
.wire-btn__label {
font-weight: 650;
}
.wire-btn:hover > .wire-btn__tooltip,
.wire-btn:focus-visible > .wire-btn__tooltip {
opacity: 1;
transform: translate(-50%, 0);
}
.wire-action {
position: relative;
display: inline-flex;
}
.wire-btn--pill {
border-radius: 999px;
}
.wire-btn--with-description {
min-height: 3.5rem;
justify-content: flex-start;
padding: 0.6rem 0.875rem;
text-align: left;
}
.wire-btn__copy {
display: grid;
min-width: 0;
gap: 0.15rem;
}
.wire-btn__description {
color: currentColor;
font-size: 0.75rem;
font-weight: 450;
line-height: 1.35;
opacity: 0.74;
}
.wire-btn__tooltip {
position: absolute;
z-index: 80;
inset-block-end: calc(100% + 0.5rem);
inset-inline-start: 50%;
width: max-content;
max-width: min(16rem, calc(100vw - 2rem));
padding: 0.4rem 0.6rem;
color: var(--wire-color-bg);
background: var(--wire-color-text);
border: 1px solid color-mix(in srgb, var(--wire-color-text) 85%, var(--wire-color-border));
border-radius: var(--wire-radius-sm);
box-shadow: var(--wire-shadow-2);
font-size: 0.75rem;
font-weight: 600;
line-height: 1.25;
text-align: center;
pointer-events: none;
opacity: 0;
transform: translate(-50%, 0.25rem);
transition:
opacity var(--wire-motion-fast) var(--wire-ease-standard),
transform var(--wire-motion-fast) var(--wire-ease-standard);
}
}
} }
+365 -1
View File
@@ -1,3 +1,5 @@
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Card { component Card {
outputs { outputs {
click(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) click(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
@@ -80,7 +82,7 @@ component Card {
data-layout='{layout}' data-layout='{layout}'
data-hover='{hover}' data-hover='{hover}'
data-align='{align}' data-align='{align}'
class='wire-next wire-next--card wire-next--color-{color} wire-next--size-{size} wire-next--variant-{variant} {class}' class='wire-component wire-next--card wire-component--color-{color} wire-component--size-{size} wire-next--variant-{variant} {class}'
> >
{#if items.length > 0} {#if items.length > 0}
<div class="wire-next__card-group"> <div class="wire-next__card-group">
@@ -308,5 +310,367 @@ component Card {
</article> </article>
{/if} {/if}
</div> </div>
<ComponentBaseStyles hidden />
}
style {
.wire-next__card-media--overlay {
aspect-ratio: 16 / 9;
min-height: 18rem;
}
.wire-next__card-media--overlay > img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
@media (max-width: 480px) {
.wire-next__card-media--overlay {
aspect-ratio: 4 / 3;
min-height: 16rem;
}
}
.wire-next--card {
--wire-card-color: var(--wire-component-color, var(--wire-color-primary));
--wire-card-padding: 1.25rem;
display: block;
width: 100%;
color: var(--wire-color-text);
}
.wire-next--card[data-size="sm"] {
--wire-card-padding: 0.85rem;
}
.wire-next--card[data-size="lg"] {
--wire-card-padding: 1.75rem;
}
.wire-next__card-panel {
position: relative;
display: flex;
overflow: hidden;
flex-direction: column;
width: 100%;
min-width: 0;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-md);
background: var(--wire-color-surface);
box-shadow: var(--wire-shadow-1);
transition:
transform var(--wire-motion-base) var(--wire-ease-emphasized),
border-color var(--wire-motion-base) ease,
box-shadow var(--wire-motion-base) var(--wire-ease-emphasized);
}
.wire-next--card[data-variant="top-border"] > .wire-next__card-panel,
.wire-next--card[data-variant="accent"] > .wire-next__card-panel {
border-top: 4px solid var(--wire-card-color);
}
.wire-next--card[data-hover="raise"] > .wire-next__card-panel:hover {
border-color: color-mix(in srgb, var(--wire-card-color) 38%, var(--wire-color-border));
box-shadow: var(--wire-shadow-3);
transform: translateY(-4px);
}
.wire-next__card-header,
.wire-next__card-footer {
display: flex;
gap: 1rem;
align-items: center;
justify-content: space-between;
padding: 0.85rem var(--wire-card-padding);
background: var(--wire-color-surface-2);
color: var(--wire-color-muted);
font-size: 0.875rem;
}
.wire-next__card-header {
border-bottom: 1px solid var(--wire-color-border);
}
.wire-next__card-footer {
margin-top: auto;
border-top: 1px solid var(--wire-color-border);
}
.wire-next__card-header-actions {
display: inline-flex;
gap: 0.2rem;
align-items: center;
}
.wire-next__card-header-actions button {
display: inline-grid;
width: 2rem;
height: 2rem;
border: 0;
border-radius: var(--wire-radius-sm);
background: transparent;
color: var(--wire-color-muted);
cursor: pointer;
place-items: center;
}
.wire-next__card-header-actions button:hover {
background: color-mix(in srgb, var(--wire-card-color) 12%, transparent);
color: var(--wire-card-color);
}
.wire-next__card-header-actions button:focus-visible {
outline: 2px solid var(--wire-card-color);
outline-offset: 1px;
}
.wire-next__card-media {
position: relative;
overflow: hidden;
min-height: 10rem;
background: var(--wire-color-surface-2);
}
.wire-next__card-media > img {
display: block;
width: 100%;
height: 100%;
min-height: inherit;
object-fit: cover;
transition: transform 420ms var(--wire-ease-emphasized);
}
.wire-next--card[data-hover="image"] .wire-next__card-panel:hover .wire-next__card-media > img {
transform: scale(1.06);
}
.wire-next__card-overlay {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
gap: 0.55rem;
padding: clamp(1.25rem, 4vw, 2rem);
background: linear-gradient(
180deg,
rgb(2 6 23 / 0.9) 0%,
rgb(2 6 23 / 0.68) 38%,
rgb(2 6 23 / 0.34) 58%,
rgb(2 6 23 / 0.86) 100%
);
color: white;
text-shadow: 0 1px 2px rgb(0 0 0 / 0.42);
}
.wire-next__card-overlay h3 {
color: white;
font-size: clamp(1.1rem, 2.2vw, 1.35rem);
}
.wire-next__card-overlay p {
max-width: 48rem;
color: #fff;
font-weight: 500;
line-height: 1.6;
text-shadow:
0 1px 2px rgb(0 0 0 / 0.9),
0 2px 8px rgb(0 0 0 / 0.62);
}
.wire-next__card-overlay .wire-next__card-subtitle {
color: rgb(255 255 255 / 0.78);
}
.wire-next__card-overlay small {
margin-top: auto;
color: rgb(255 255 255 / 0.88);
font-weight: 600;
text-shadow: 0 1px 2px rgb(0 0 0 / 0.55);
}
.wire-next__card-body {
display: grid;
gap: 0.65rem;
min-width: 0;
padding: var(--wire-card-padding);
}
.wire-next__card-body[data-scrollable="true"] {
max-height: var(--wire-card-max-height);
overflow: auto;
overscroll-behavior: contain;
scrollbar-color: var(--wire-card-color) transparent;
scrollbar-width: thin;
}
.wire-next__card-body h3,
.wire-next__card-body p,
.wire-next__card-overlay h3,
.wire-next__card-overlay p {
margin: 0;
}
.wire-next__card-body p {
color: var(--wire-color-muted);
line-height: 1.65;
}
.wire-next__card-subtitle {
color: var(--wire-color-muted);
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.wire-next__card-action {
display: inline-flex;
gap: 0.25rem;
align-items: center;
width: fit-content;
margin-top: 0.2rem;
color: var(--wire-card-color);
font-weight: 700;
text-decoration: none;
}
.wire-next__card-action:hover {
text-decoration: underline;
text-underline-offset: 0.2em;
}
.wire-next__card-navigation {
background: var(--wire-color-surface-2);
}
.wire-next__card-tabs {
display: flex;
overflow-x: auto;
}
.wire-next__card-tabs button {
min-height: 3rem;
flex: 1 0 auto;
padding-inline: 1rem;
border: 0;
border-bottom: 2px solid transparent;
background: transparent;
color: var(--wire-color-muted);
cursor: pointer;
font-weight: 700;
}
.wire-next__card-tabs button[data-active="true"] {
border-color: var(--wire-card-color);
color: var(--wire-color-text);
}
.wire-next__card-navigation-select {
display: none;
width: calc(100% - 2rem);
min-height: 2.75rem;
margin: 1rem;
border: 1px solid var(--wire-color-border);
border-radius: var(--wire-radius-sm);
background: var(--wire-color-surface);
color: var(--wire-color-text);
}
.wire-next__card-alert {
display: flex;
gap: 0.35rem;
padding: 0.8rem var(--wire-card-padding);
background: color-mix(in srgb, var(--wire-card-color) 14%, var(--wire-color-surface-2));
color: var(--wire-color-text);
font-size: 0.875rem;
}
.wire-next__card-empty {
display: grid;
min-height: 12rem;
color: var(--wire-color-muted);
place-content: center;
place-items: center;
}
.wire-next__card-empty > span {
margin-bottom: 0.75rem;
font-size: 2.25rem;
}
.wire-next--card[data-align="center"] .wire-next__card-body {
text-align: center;
place-items: center;
}
.wire-next--card[data-layout="horizontal"] > .wire-next__card-panel {
display: grid;
grid-template-columns: minmax(12rem, 42%) minmax(0, 1fr);
}
.wire-next--card[data-layout="horizontal"] .wire-next__card-media {
grid-row: 1 / span 4;
min-height: 100%;
}
.wire-next__card-group {
display: grid;
grid-template-columns: repeat(var(--wire-card-columns, 3), minmax(0, 1fr));
}
.wire-next__card-group > .wire-next__card-panel {
border-radius: 0;
box-shadow: none;
}
.wire-next__card-group > .wire-next__card-panel:not(:first-child) {
margin-inline-start: -1px;
}
.wire-next__card-group > .wire-next__card-panel:first-child {
border-start-start-radius: var(--wire-radius-md);
border-end-start-radius: var(--wire-radius-md);
}
.wire-next__card-group > .wire-next__card-panel:last-child {
border-start-end-radius: var(--wire-radius-md);
border-end-end-radius: var(--wire-radius-md);
}
@media (max-width: 768px) {
.wire-next--card[data-layout="horizontal"] > .wire-next__card-panel {
display: flex;
}
.wire-next--card[data-layout="horizontal"] .wire-next__card-media {
min-height: 12rem;
}
.wire-next__card-group {
grid-template-columns: 1fr;
}
.wire-next__card-group > .wire-next__card-panel:not(:first-child) {
margin-top: -1px;
margin-inline-start: 0;
}
.wire-next__card-group > .wire-next__card-panel {
border-radius: 0;
}
.wire-next__card-group > .wire-next__card-panel:first-child {
border-start-start-radius: var(--wire-radius-md);
border-start-end-radius: var(--wire-radius-md);
}
.wire-next__card-group > .wire-next__card-panel:last-child {
border-end-start-radius: var(--wire-radius-md);
border-end-end-radius: var(--wire-radius-md);
}
}
@media (max-width: 480px) {
.wire-next__card-tabs:has(+ .wire-next__card-navigation-select) {
display: none;
}
.wire-next__card-navigation-select {
display: block;
}
}
} }
} }
+34 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Checkbox { component Checkbox {
outputs { outputs {
input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -43,7 +47,7 @@ size: string = "default"
view { view {
<div <div
{...attrs} {...attrs}
class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--choice-field wire-next--checkbox-field {class}" class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--choice-field wire-next--checkbox-field {class}"
data-inline="{inline}" data-inline="{inline}"
data-invalid="{error ? 'true' : 'false'}" data-invalid="{error ? 'true' : 'false'}"
data-orientation="{orientation}" data-orientation="{orientation}"
@@ -172,5 +176,34 @@ size: string = "default"
{error} {error}
</small> </small>
</div> </div>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next__checkbox-content {
display: grid;
width: 100%;
min-width: 0;
align-items: start;
grid-template-columns: minmax(0, 1fr);
}
.wire-next__checkbox-slot {
display: block;
min-width: 0;
flex: 1 1 auto;
color: var(--wire-color-muted);
font-size: 0.75rem;
line-height: 1.45;
}
.wire-next__checkbox-slot:empty {
display: none;
}
.wire-next__checkbox-slot :is(a, button) {
color: var(--wire-field-color);
}
} }
} }
+12 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Input { component Input {
outputs { outputs {
input(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]) input(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])
@@ -52,7 +56,7 @@ size: string = "default"
client function handleKeyup(sourceEvent) { sourceEvent.stopPropagation(); output.keyup({ key: sourceEvent.key, value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) } client function handleKeyup(sourceEvent) { sourceEvent.stopPropagation(); output.keyup({ key: sourceEvent.key, value: sourceEvent.currentTarget.value, name: name, sourceEvent: sourceEvent }) }
} }
view { view {
<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 {...attrs} class="wire-component wire-component--color-{color} wire-component--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"> <div class="wire-next__field-heading">
<label class="{hiddenLabel ? 'wire-next__sr-only' : ''}" for="{id || name}">{label}</label> <label class="{hiddenLabel ? 'wire-next__sr-only' : ''}" for="{id || name}">{label}</label>
{#if cornerHint}<span class="wire-next__field-hint">{cornerHint}</span>{/if} {#if cornerHint}<span class="wire-next__field-hint">{cornerHint}</span>{/if}
@@ -91,5 +95,12 @@ size: string = "default"
{#if helperText}<small id="{(id || name) + '-help'}" class="wire-next__field-help">{helperText}</small>{/if} {#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> <small id="{(id || name) + '-error'}" class="wire-next__field-error" data-error="{name}">{error}</small>
</div> </div>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next--input { width: 100%; min-width: 0; }
.wire-next--input[data-invalid="true"] { --wire-component-color: var(--wire-color-danger); }
} }
} }
+43 -3
View File
@@ -9,9 +9,49 @@ component Progress {
class: string = "" class: string = ""
} }
view { view {
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--progress {class}"> <div class="wire-progress-component {class}" data-color="{color}" data-size="{size}">
<div class="wire-next__row"><span>{label}</span>{#if showValue}<strong>{value}%</strong>{/if}</div> <div class="wire-progress-component__row"><span>{label}</span>{#if showValue}<strong>{value}%</strong>{/if}</div>
<progress value="{value}" max="{max}"></progress> <progress class="wire-progress-component__track" value="{value}" max="{max}" aria-label="{label}"></progress>
</div> </div>
} }
style {
.wire-progress-component {
--wire-progress-color: var(--wire-color-primary);
display: grid;
width: 100%;
gap: 0.5rem;
color: var(--wire-color-text);
font-size: 0.875rem;
}
.wire-progress-component[data-color="secondary"] { --wire-progress-color: var(--wire-color-secondary); }
.wire-progress-component[data-color="success"] { --wire-progress-color: var(--wire-color-success); }
.wire-progress-component[data-color="warning"] { --wire-progress-color: var(--wire-color-warning); }
.wire-progress-component[data-color="danger"] { --wire-progress-color: var(--wire-color-danger); }
.wire-progress-component[data-color="info"] { --wire-progress-color: var(--wire-color-info); }
.wire-progress-component[data-size="xs"] { font-size: 0.75rem; }
.wire-progress-component[data-size="lg"],
.wire-progress-component[data-size="xl"] { font-size: 1rem; }
.wire-progress-component__row {
display: flex;
justify-content: space-between;
gap: 1rem;
}
.wire-progress-component__track {
width: 100%;
height: 0.6rem;
overflow: hidden;
border: 0;
border-radius: 999px;
background: var(--wire-color-surface-2);
accent-color: var(--wire-progress-color);
}
.wire-progress-component__track::-webkit-progress-bar { background: var(--wire-color-surface-2); }
.wire-progress-component__track::-webkit-progress-value { background: var(--wire-progress-color); }
.wire-progress-component__track::-moz-progress-bar { background: var(--wire-progress-color); }
}
} }
+12 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Radio { component Radio {
outputs { outputs {
input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -39,7 +43,7 @@ size: string = "default"
client function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } client function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() }
} }
view { view {
<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 {...attrs} class="wire-component wire-component--color-{color} wire-component--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> <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} {#if options.length}
<div class="wire-next__radio-group" role="radiogroup" aria-label="{hiddenLabel ? label : ''}" aria-invalid="{error ? 'true' : 'false'}"> <div class="wire-next__radio-group" role="radiogroup" aria-label="{hiddenLabel ? label : ''}" aria-invalid="{error ? 'true' : 'false'}">
@@ -55,5 +59,12 @@ size: string = "default"
{/if} {/if}
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small> {#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div> </div>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next--radio-field { width: 100%; min-width: 0; }
.wire-next--radio-field[data-invalid="true"] { --wire-component-color: var(--wire-color-danger); }
} }
} }
+16 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Select { component Select {
outputs { outputs {
input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -47,7 +51,7 @@ size: string = "default"
client function handleInvalid(sourceEvent) { output.invalid({ name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) } client function handleInvalid(sourceEvent) { output.invalid({ name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) }
} }
view { view {
<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 {...attrs} class="wire-component wire-component--color-{color} wire-component--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-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}"> <div class="wire-next__field-control" data-icon-position="{iconPosition}">
{#if icon}<span class="{icon} wire-next__field-icon" aria-hidden="true"></span>{/if} {#if icon}<span class="{icon} wire-next__field-icon" aria-hidden="true"></span>{/if}
@@ -60,5 +64,16 @@ size: string = "default"
{#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if} {#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}
<small class="wire-next__field-error" data-error="{name}">{error}</small> <small class="wire-next__field-error" data-error="{name}">{error}</small>
</div> </div>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next--select select {
width: 100%;
min-height: 2.65rem;
margin: 0;
line-height: 1.35;
}
} }
} }
+36 -2
View File
@@ -7,8 +7,42 @@ component Skeleton {
class: string = "" class: string = ""
} }
view { view {
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--skeleton wire-next--size-{size} {class}" role="status" aria-label="{label}"> <div class="wire-skeleton-component {class}" data-color="{color}" data-size="{size}" role="status" aria-label="{label}">
{#if "Skeleton" === "Skeleton"}{#each Array(lines).fill(0) as line}<span></span>{/each}{:else}<i aria-hidden="true"></i>{/if} {#each Array(lines).fill(0) as line}<span class="wire-skeleton-component__line"></span>{/each}
</div> </div>
} }
style {
.wire-skeleton-component {
--wire-skeleton-highlight: var(--wire-color-border);
display: grid;
width: min(100%, 24rem);
gap: 0.55rem;
}
.wire-skeleton-component[data-size="xs"] { gap: 0.35rem; }
.wire-skeleton-component[data-size="lg"],
.wire-skeleton-component[data-size="xl"] { gap: 0.75rem; }
.wire-skeleton-component[data-color="secondary"] { --wire-skeleton-highlight: var(--wire-color-secondary-soft); }
.wire-skeleton-component[data-color="primary"] { --wire-skeleton-highlight: var(--wire-color-primary-soft); }
.wire-skeleton-component__line {
height: 0.8rem;
border-radius: 999px;
background: linear-gradient(90deg, var(--wire-color-surface-2), var(--wire-skeleton-highlight), var(--wire-color-surface-2));
background-size: 200% 100%;
animation: wire-skeleton-component-shimmer 1.4s infinite;
}
.wire-skeleton-component__line:last-child { width: 68%; }
@keyframes wire-skeleton-component-shimmer {
from { background-position: 200% 0; }
to { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
.wire-skeleton-component__line { animation: none; }
}
}
} }
+37 -2
View File
@@ -7,8 +7,43 @@ component Spinner {
class: string = "" class: string = ""
} }
view { view {
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--spinner wire-next--size-{size} {class}" role="status" aria-label="{label}"> <div class="wire-spinner-component {class}" data-color="{color}" data-size="{size}" role="status" aria-label="{label}">
{#if "Spinner" === "Skeleton"}{#each Array(lines).fill(0) as line}<span></span>{/each}{:else}<i aria-hidden="true"></i>{/if} <i class="wire-spinner-component__indicator" aria-hidden="true"></i>
</div> </div>
} }
style {
.wire-spinner-component {
--wire-spinner-size: 1.5rem;
--wire-spinner-color: var(--wire-color-primary);
display: inline-grid;
place-items: center;
}
.wire-spinner-component[data-size="xs"] { --wire-spinner-size: 0.875rem; }
.wire-spinner-component[data-size="sm"] { --wire-spinner-size: 1.125rem; }
.wire-spinner-component[data-size="lg"] { --wire-spinner-size: 2rem; }
.wire-spinner-component[data-size="xl"] { --wire-spinner-size: 2.5rem; }
.wire-spinner-component[data-color="secondary"] { --wire-spinner-color: var(--wire-color-secondary); }
.wire-spinner-component[data-color="success"] { --wire-spinner-color: var(--wire-color-success); }
.wire-spinner-component[data-color="warning"] { --wire-spinner-color: var(--wire-color-warning); }
.wire-spinner-component[data-color="danger"] { --wire-spinner-color: var(--wire-color-danger); }
.wire-spinner-component[data-color="info"] { --wire-spinner-color: var(--wire-color-info); }
.wire-spinner-component__indicator {
display: block;
width: var(--wire-spinner-size);
height: var(--wire-spinner-size);
border: 2px solid var(--wire-color-border);
border-top-color: var(--wire-spinner-color);
border-radius: 50%;
animation: wire-spinner-component-spin 700ms linear infinite;
}
@keyframes wire-spinner-component-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
.wire-spinner-component__indicator { animation-duration: 1.8s; }
}
}
} }
+51 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Switch { component Switch {
outputs { outputs {
input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -33,10 +37,56 @@ component Switch {
client function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() } client function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() }
} }
view { view {
<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 {...attrs} class="wire-component wire-component--color-{color} wire-component--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> <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> <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> {#if helperText}<small class="wire-next__field-help">{helperText}</small>{/if}<small class="wire-next__field-error" data-error="{name}">{error}</small>
</div> </div>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next--switch input {
appearance: none;
position: relative;
width: 2.5rem;
height: 1.4rem;
border: 1px solid var(--wire-color-border);
border-radius: 999px;
background: var(--wire-color-surface-2);
transition: background var(--wire-motion-fast) var(--wire-ease-standard);
}
.wire-next--switch {
min-height: 2.65rem;
justify-content: flex-start;
}
.wire-next--switch > span:last-child {
line-height: 1.35;
}
.wire-next--switch input::after {
position: absolute;
top: 0.15rem;
left: 0.15rem;
width: 1rem;
height: 1rem;
border-radius: 999px;
background: var(--wire-color-text);
content: "";
transition: transform var(--wire-motion-fast) var(--wire-ease-standard);
}
.wire-next--switch input:checked {
border-color: var(--wire-field-color);
background: var(--wire-field-color);
}
.wire-next--switch input:checked::after {
background: var(--wire-color-primary-contrast, #fff);
transform: translateX(1.1rem);
}
} }
} }
+12 -1
View File
@@ -1,3 +1,7 @@
import FieldStyles from "../styles/FieldStyles.wrn"
import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn"
component Textarea { component Textarea {
outputs { outputs {
input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) input(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
@@ -42,7 +46,7 @@ size: string = "default"
} }
} }
view { view {
<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 {...attrs} class="wire-component wire-component--color-{color} wire-component--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-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}"> <div class="wire-next__field-control" data-icon-position="{iconPosition}">
{#if icon}<span class="{icon} wire-next__field-icon" aria-hidden="true"></span>{/if} {#if icon}<span class="{icon} wire-next__field-icon" aria-hidden="true"></span>{/if}
@@ -52,5 +56,12 @@ size: string = "default"
{#if helperText}<small id="{(id || name) + '-help'}" class="wire-next__field-help">{helperText}</small>{/if} {#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> <small id="{(id || name) + '-error'}" class="wire-next__field-error" data-error="{name}">{error}</small>
</div> </div>
<FieldStyles hidden />
<ComponentBaseStyles hidden />
}
style {
.wire-next--textarea { width: 100%; min-width: 0; }
.wire-next--textarea[data-invalid="true"] { --wire-component-color: var(--wire-color-danger); }
} }
} }
+5 -6140
View File
File diff suppressed because it is too large Load Diff