Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b728a3e5d | ||
|
|
d0aded0392 | ||
|
|
c81dedff17 | ||
|
|
44ba847210 | ||
|
|
798f06d4c0 | ||
|
|
173e230d7f | ||
|
|
bbec4cc7bb | ||
|
|
504bd4358f | ||
|
|
e543fd026d | ||
|
|
d51662826d | ||
|
|
e2d9ea1ece | ||
|
|
58ba2f2046 | ||
|
|
304819dfe9 | ||
|
|
07d8fb59d6 | ||
|
|
13dfa31d19 | ||
|
|
c6fc0f1f63 | ||
|
|
7ff5b3e8c5 | ||
|
|
569365143b | ||
|
|
69b6cd431f | ||
|
|
2ca2d02b22 | ||
|
|
0013c0771d | ||
|
|
0b8856b3b5 | ||
|
|
45e6fd3cb9 | ||
|
|
54f5309fca | ||
|
|
944f83d3f4 | ||
|
|
a75779fa4d | ||
|
|
2b4083c6db | ||
|
|
aa2595ec01 | ||
|
|
b3e5e5b999 | ||
|
|
3888453e0d | ||
|
|
b95bdc6e77 | ||
|
|
1745d8d676 | ||
|
|
f72aec7c8c | ||
|
|
33730c68ab | ||
|
|
5ce45b4973 | ||
|
|
dcdb5e766d | ||
|
|
a3e21163c1 | ||
|
|
c5326f7622 | ||
|
|
eaea2c5f72 | ||
|
|
ca8f746f41 | ||
|
|
94ae40d8bd | ||
|
|
0d3ec79ee4 | ||
|
|
c0c09426ff | ||
|
|
14e2878417 | ||
|
|
180239ef4c | ||
|
|
12beb6f4ba | ||
|
|
6dbc75c370 | ||
|
|
7cee13526e | ||
|
|
3bb096057e | ||
|
|
646d16f83d | ||
|
|
df4c1d3e7d | ||
|
|
17dc7c1a06 | ||
|
|
c72cbbd780 | ||
|
|
1cda2a01b3 | ||
|
|
9ca1cc6b0f | ||
|
|
aa6badbd31 | ||
|
|
4a3ee3baa7 | ||
|
|
95ca1c0625 | ||
|
|
d22824fa62 | ||
|
|
973d580bc5 | ||
|
|
8a8328a308 | ||
|
|
0f915c3c98 | ||
|
|
9aa13fb4db | ||
|
|
9070a1ef9c | ||
|
|
4230de7065 | ||
|
|
0006aef2c4 | ||
|
|
7dfca4a190 | ||
|
|
29bbeefe92 | ||
|
|
98445c2ec7 | ||
|
|
17a535d4dc | ||
|
|
afb14c2fbf | ||
|
|
2c6e6f6de3 | ||
|
|
cade812569 | ||
|
|
936488ac06 | ||
|
|
959ed24009 |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/ai",
|
"name": "@wrnexus/ai",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
|
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/authz",
|
"name": "@wrnexus/authz",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/authz — part of the WrNexus framework.",
|
"description": "@wrnexus/authz — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ Every command accepts an optional `[app-dir]` (defaults to `.`). Commands that r
|
|||||||
| `wrnexus workspace <name>` | Scaffold a monorepo (`apps/*` + shared `packages/*`). |
|
| `wrnexus workspace <name>` | Scaffold a monorepo (`apps/*` + shared `packages/*`). |
|
||||||
| `wrnexus workspace add <name>` | Add and register an app in the current workspace. |
|
| `wrnexus workspace add <name>` | Add and register an app in the current workspace. |
|
||||||
| `wrnexus gateway [--port=3000]` | Serve every workspace app behind one port, routed by domain. |
|
| `wrnexus gateway [--port=3000]` | Serve every workspace app behind one port, routed by domain. |
|
||||||
|
| `wrnexus production [workspace-dir]` | Build, migrate, and serve every workspace app in production. |
|
||||||
| `wrnexus generate <type> <name>` | Scaffold a `page` \| `component` \| `api` \| `schema`. |
|
| `wrnexus generate <type> <name>` | Scaffold a `page` \| `component` \| `api` \| `schema`. |
|
||||||
| `wrnexus generate routes` | Regenerate the typed routes file (`app/routes.gen.ts`). |
|
| `wrnexus generate routes` | Regenerate the typed routes file (`app/routes.gen.ts`). |
|
||||||
| `wrnexus generate docker` | Scaffold `Dockerfile`, `.dockerignore`, and `docker-compose.yml`. |
|
| `wrnexus generate docker` | Scaffold `Dockerfile`, `.dockerignore`, and `docker-compose.yml`. |
|
||||||
@@ -168,6 +169,17 @@ wrnexus workspace acme
|
|||||||
wrnexus gateway --port=3000
|
wrnexus gateway --port=3000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For a complete production start, use the first-class workspace orchestrator:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
wrnexus production --host=0.0.0.0 --port=3000
|
||||||
|
```
|
||||||
|
|
||||||
|
It builds every registered app, applies default and named-database SQL migrations
|
||||||
|
when present, and starts the production gateway only after preparation succeeds.
|
||||||
|
Use `--prepare-only`, `--no-build`, or `--no-migrate` when deployment stages are
|
||||||
|
managed separately; `--environment=<name>` selects another workspace environment.
|
||||||
|
|
||||||
From a workspace root, add and register another app in one command:
|
From a workspace root, add and register another app in one command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
+14
-12
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/cli",
|
"name": "@wrnexus/cli",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/cli — part of the WrNexus framework.",
|
"description": "@wrnexus/cli — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
@@ -28,16 +28,18 @@
|
|||||||
"wrnexus": "./dist/index.js"
|
"wrnexus": "./dist/index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/core": "^0.2.31",
|
"@wrnexus/core": "^0.3.6",
|
||||||
"@wrnexus/router": "^0.2.31",
|
"@wrnexus/router": "^0.3.6",
|
||||||
"@wrnexus/csr": "^0.2.31",
|
"@wrnexus/csr": "^0.3.6",
|
||||||
"@wrnexus/compiler": "^0.2.31",
|
"@wrnexus/compiler": "^0.3.6",
|
||||||
"@wrnexus/styles": "^0.2.31",
|
"@wrnexus/styles": "^0.3.6",
|
||||||
"@wrnexus/dev-server": "^0.2.31",
|
"@wrnexus/dev-server": "^0.3.6",
|
||||||
"@wrnexus/ui": "^0.2.31",
|
"@wrnexus/ui": "^0.3.6",
|
||||||
"@wrnexus/validation": "^0.2.31",
|
"@wrnexus/validation": "^0.3.6",
|
||||||
"@wrnexus/i18n": "^0.2.31",
|
"@wrnexus/i18n": "^0.3.6",
|
||||||
"@wrnexus/db": "^0.2.31"
|
"@wrnexus/db": "^0.3.6",
|
||||||
|
"@wrnexus/plugin": "^0.3.6",
|
||||||
|
"@wrnexus/syntax": "^0.3.6"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
|||||||
@@ -8,6 +8,19 @@ Part of the **WrNexus** framework — an SSR-first, Bun-native full-stack web fr
|
|||||||
|
|
||||||
`@wrnexus/compiler` turns `.wrn` source into TypeScript that targets the framework's runtime primitives. A `.wrn` file declares either a `page` (a route) or a `component` (a reusable, prop-driven fragment) with blocks for `state`, `view` (plain HTML), `seo`, `style`, `functions`, `api`, `ssr`/`client` data bindings, and `realtime` websocket handlers. The pipeline is `source → Lexer → parse() → PageAst → generate() → TypeScript`. It is a build/server-side library — the WrNexus dev loader calls it to compile `.wrn` files on the fly, surfacing `ParseError` as a readable error page.
|
`@wrnexus/compiler` turns `.wrn` source into TypeScript that targets the framework's runtime primitives. A `.wrn` file declares either a `page` (a route) or a `component` (a reusable, prop-driven fragment) with blocks for `state`, `view` (plain HTML), `seo`, `style`, `functions`, `api`, `ssr`/`client` data bindings, and `realtime` websocket handlers. The pipeline is `source → Lexer → parse() → PageAst → generate() → TypeScript`. It is a build/server-side library — the WrNexus dev loader calls it to compile `.wrn` files on the fly, surfacing `ParseError` as a readable error page.
|
||||||
|
|
||||||
|
Static ES module imports may appear before the root declaration. Imported values are
|
||||||
|
available to server-rendered expressions, including component props:
|
||||||
|
|
||||||
|
```wrn
|
||||||
|
import { appUrl } from "@wrnexus/helpers";
|
||||||
|
|
||||||
|
layout PublicLayout {
|
||||||
|
view {
|
||||||
|
<PublicHeader signInHref="{appUrl('sso', '/sign-in')}" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -77,11 +90,12 @@ class Lexer {
|
|||||||
Exported type-only symbols describing the parsed tree:
|
Exported type-only symbols describing the parsed tree:
|
||||||
|
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `PageAst` | Root node: `kind` (`"page" \| "component"`), `name`, optional `layout`, `props`, `states`, `seo`, `view`, `styles`, `functions`, `dataApis`, `modeFunctions`, `apis`, `realtimes`. |
|
| `PageAst` | Root node including top-level `imports`, `kind`, `name`, `types`, typed `props`, typed `states`, `view`, styles, functions, data APIs, lifecycle, and routes. |
|
||||||
| `ViewNode` | `{ type: "text"; value }` or `{ type: "element"; tag; attrs; children }`. |
|
| `ViewNode` | `{ type: "text"; value }` or `{ type: "element"; tag; attrs; children }`. |
|
||||||
| `Attr` | `{ name; value; event; boolean? }` — `event` marks `@event` bindings. |
|
| `Attr` | `{ name; value; event; boolean? }` — `event` marks `@event` bindings. |
|
||||||
| `StateDecl` | `{ name; expr }` — a `state x = <expr>` declaration. |
|
| `StateDecl` | `{ name; valueType?; expr }` — a typed `state x: Type = <expr>` declaration. |
|
||||||
|
| `PropDecl` | `{ name; valueType?; required; default }` — a typed prop declaration. |
|
||||||
| `SeoBlock` | `Record<string, string>` from the `seo { ... }` block. |
|
| `SeoBlock` | `Record<string, string>` from the `seo { ... }` block. |
|
||||||
| `ApiBlock` | `{ method; path; body }` — a top-level `api METHOD /path { ... }`. |
|
| `ApiBlock` | `{ method; path; body }` — a top-level `api METHOD /path { ... }`. |
|
||||||
| `DataApiBlock` | `{ mode; name; method; path; body }` — an `api` inside an `ssr`/`client` block. |
|
| `DataApiBlock` | `{ mode; name; method; path; body }` — an `api` inside an `ssr`/`client` block. |
|
||||||
@@ -147,12 +161,14 @@ lx.next(); // { type: "lbrace", value: "{", pos: 10 }
|
|||||||
A file opens with `page <Name>` or `component <Name>` followed by a `{ ... }` body containing zero or more members:
|
A file opens with `page <Name>` or `component <Name>` followed by a `{ ... }` body containing zero or more members:
|
||||||
|
|
||||||
- `layout = "<name>"` — selects `app/layouts/<name>.wrn` (pages only).
|
- `layout = "<name>"` — selects `app/layouts/<name>.wrn` (pages only).
|
||||||
- `props { name = <default> ... }` — component props; each default's type drives coercion.
|
- `types { <TypeScript declarations> }` — reusable interfaces and aliases for the current file.
|
||||||
- `state <ident> = <expr>` — reactive state seeded from a raw JS expression.
|
- `props { name: Type = <default> ... }` — typed component props. Omit `= <default>` to make a prop required. Legacy inferred props remain supported.
|
||||||
|
- `@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. The annotation is optional for backward compatibility.
|
||||||
- `view { <html> }` — plain HTML with `{expr}` interpolation in text and attributes, hyphenated attributes, boolean attributes, `@event="..."` client bindings, and `<!-- comments -->`. Attribute expressions that reference `state` keep an SSR value and update reactively in the browser.
|
- `view { <html> }` — plain HTML with `{expr}` interpolation in text and attributes, hyphenated attributes, boolean attributes, `@event="..."` client bindings, and `<!-- comments -->`. Attribute expressions that reference `state` keep an SSR value and update reactively in the browser.
|
||||||
- `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 { <raw js> }` — shared server-side helpers (repeatable).
|
- `functions { <TypeScript> }` — helpers with typed parameters and return values. Types remain in server output and are safely erased from browser behavior code.
|
||||||
- `api <METHOD> <path> { <raw js> }` — route handler, lowered to a `METHOD` export (repeatable).
|
- `api <METHOD> <path> { <raw js> }` — route handler, lowered to a `METHOD` export (repeatable).
|
||||||
- `ssr { ... }` / `client { ... }` — data blocks holding `api <name> <METHOD> <path> { ... }` bindings and their own `functions { ... }`.
|
- `ssr { ... }` / `client { ... }` — data blocks holding `api <name> <METHOD> <path> { ... }` bindings and their own `functions { ... }`.
|
||||||
- `realtime <name> { on <evt>(<args>) { <raw js> } ... }` — websocket handlers, lowered to a `websocket` export.
|
- `realtime <name> { on <evt>(<args>) { <raw js> } ... }` — websocket handlers, lowered to a `websocket` export.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/compiler",
|
"name": "@wrnexus/compiler",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/compiler — part of the WrNexus framework.",
|
"description": "@wrnexus/compiler — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
@@ -20,6 +20,9 @@
|
|||||||
"import": "./dist/index.js"
|
"import": "./dist/index.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@wrnexus/syntax": "^0.3.6"
|
||||||
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/core",
|
"name": "@wrnexus/core",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/core — part of the WrNexus framework.",
|
"description": "@wrnexus/core — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
|||||||
@@ -50,12 +50,13 @@ getRealtimeRuntime(): string // → REALTIME_RUNTIME
|
|||||||
Applied to any subtree containing `data-scope`. Expressions are parsed by a tiny eval-free evaluator, so a strict CSP with no `unsafe-eval` works.
|
Applied to any subtree containing `data-scope`. Expressions are parsed by a tiny eval-free evaluator, so a strict CSP with no `unsafe-eval` works.
|
||||||
|
|
||||||
| Directive | Purpose |
|
| Directive | Purpose |
|
||||||
| -------------------------------------------------- | ----------------------------------------------------------------------- |
|
| -------------------------------------------------------- | ----------------------------------------------------------------------- |
|
||||||
| `data-scope="count: 0, name: 'x'"` | Declare reactive state on a subtree |
|
| `data-scope="count: 0, name: 'x'"` | Declare reactive state on a subtree |
|
||||||
| `data-on-<event>="count++"` | Run a statement in scope on a DOM event |
|
| `data-on-<event>="count++"` | Run a statement in scope on a DOM event |
|
||||||
| `data-text="expr"` | Bind an element's `textContent` to an expression |
|
| `data-text="expr"` | Bind an element's `textContent` to an expression |
|
||||||
| `data-show="expr"` | Toggle visibility (`display`) on truthiness |
|
| `data-show="expr"` | Toggle visibility (`display`) on truthiness |
|
||||||
| `data-for="item in list"` (opt. `item, i in list`) | Per-item list rendering template |
|
| `data-for="item in list"` (opt. index and `key item.id`) | Per-item rendering; stable keys preserve DOM identity during reorder |
|
||||||
|
| `data-key="item.id"` | Alternative key declaration for `data-for` templates |
|
||||||
| `{{expr}}` or `{expr}` | Interpolation inside text nodes and attribute values |
|
| `{{expr}}` or `{expr}` | Interpolation inside text nodes and attribute values |
|
||||||
| `data-wrnexus-csr="id"` | Target for a generated CSR fetch binding (fetches `/__wrnexus/csr?...`) |
|
| `data-wrnexus-csr="id"` | Target for a generated CSR fetch binding (fetches `/__wrnexus/csr?...`) |
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/csr",
|
"name": "@wrnexus/csr",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/csr — part of the WrNexus framework.",
|
"description": "@wrnexus/csr — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/core": "^0.2.31"
|
"@wrnexus/core": "^0.3.6"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/db",
|
"name": "@wrnexus/db",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/db — part of the WrNexus framework.",
|
"description": "@wrnexus/db — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/dev-server",
|
"name": "@wrnexus/dev-server",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/dev-server — part of the WrNexus framework.",
|
"description": "@wrnexus/dev-server — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
@@ -25,18 +25,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/core": "^0.2.31",
|
"@wrnexus/core": "^0.3.6",
|
||||||
"@wrnexus/router": "^0.2.31",
|
"@wrnexus/dev-toolbar": "^0.3.6",
|
||||||
"@wrnexus/ssr": "^0.2.31",
|
"@wrnexus/router": "^0.3.6",
|
||||||
"@wrnexus/csr": "^0.2.31",
|
"@wrnexus/ssr": "^0.3.6",
|
||||||
"@wrnexus/compiler": "^0.2.31",
|
"@wrnexus/csr": "^0.3.6",
|
||||||
"@wrnexus/styles": "^0.2.31",
|
"@wrnexus/compiler": "^0.3.6",
|
||||||
"@wrnexus/ui": "^0.2.31",
|
"@wrnexus/styles": "^0.3.6",
|
||||||
"@wrnexus/validation": "^0.2.31",
|
"@wrnexus/ui": "^0.3.6",
|
||||||
"@wrnexus/i18n": "^0.2.31",
|
"@wrnexus/validation": "^0.3.6",
|
||||||
"@wrnexus/db": "^0.2.31",
|
"@wrnexus/i18n": "^0.3.6",
|
||||||
"@wrnexus/pubsub": "^0.2.31",
|
"@wrnexus/db": "^0.3.6",
|
||||||
"@wrnexus/uploader": "^0.2.31"
|
"@wrnexus/pubsub": "^0.3.6",
|
||||||
|
"@wrnexus/uploader": "^0.3.6",
|
||||||
|
"@wrnexus/plugin": "^0.3.6"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# @wrnexus/dev-toolbar
|
||||||
|
|
||||||
|
Development-only page quality toolbar for WRNexusJS.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Runtime, resource and unhandled promise error capture
|
||||||
|
- Accessibility, SEO, image, media, color, HTML, form, link, responsive and security checks
|
||||||
|
- Performance and network observations
|
||||||
|
- Element highlighting and issue filtering
|
||||||
|
- Server-side issue collector
|
||||||
|
- Development-only asset strings for direct serving by `@wrnexus/dev-server`
|
||||||
|
- Safe open-in-editor helper
|
||||||
|
|
||||||
|
## Dev-server integration
|
||||||
|
|
||||||
|
Serve `DEV_TOOLBAR_RUNTIME` at `/__wrnexus/dev-toolbar.js` and `DEV_TOOLBAR_CSS` at `/__wrnexus/dev-toolbar.css`, then inject this before `</body>` in development:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script type="module" src="/__wrnexus/dev-toolbar.js" data-wrnexus-dev-toolbar></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
The browser runtime exposes `window.__wrnexusDevToolbar`.
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "@wrnexus/dev-toolbar",
|
||||||
|
"version": "0.3.6",
|
||||||
|
"type": "module",
|
||||||
|
"description": "@wrnexus/dev-toolbar — part of the WrNexus framework.",
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"module": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"engines": {
|
||||||
|
"bun": ">=1.3.0"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
"access": "restricted"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"import": "./dist/index.js"
|
||||||
|
},
|
||||||
|
"./client": {
|
||||||
|
"types": "./dist/client/index.d.ts",
|
||||||
|
"import": "./dist/client/index.js"
|
||||||
|
},
|
||||||
|
"./server": {
|
||||||
|
"types": "./dist/server/index.d.ts",
|
||||||
|
"import": "./dist/server/index.js"
|
||||||
|
},
|
||||||
|
"./types": {
|
||||||
|
"types": "./dist/types.d.ts",
|
||||||
|
"import": "./dist/types.js"
|
||||||
|
},
|
||||||
|
"./rules": {
|
||||||
|
"types": "./dist/rules/index.d.ts",
|
||||||
|
"import": "./dist/rules/index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/encryption",
|
"name": "@wrnexus/encryption",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/encryption — part of the WrNexus framework.",
|
"description": "@wrnexus/encryption — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/helpers",
|
"name": "@wrnexus/helpers",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
|
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/core": "^0.2.31"
|
"@wrnexus/core": "^0.3.6"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/i18n",
|
"name": "@wrnexus/i18n",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/i18n — part of the WrNexus framework.",
|
"description": "@wrnexus/i18n — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/core": "^0.2.31"
|
"@wrnexus/core": "^0.3.6"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/jwt",
|
"name": "@wrnexus/jwt",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/jwt — part of the WrNexus framework.",
|
"description": "@wrnexus/jwt — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/mobile",
|
"name": "@wrnexus/mobile",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/mobile — part of the WrNexus framework.",
|
"description": "@wrnexus/mobile — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/native": "^0.2.31"
|
"@wrnexus/native": "^0.3.6"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/native",
|
"name": "@wrnexus/native",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/native — part of the WrNexus framework.",
|
"description": "@wrnexus/native — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/oauth",
|
"name": "@wrnexus/oauth",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/oauth — part of the WrNexus framework.",
|
"description": "@wrnexus/oauth — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# @wrnexus/plugin
|
||||||
|
|
||||||
|
Deterministic WRNexusJS plugin contracts for configuration, AST/code transforms,
|
||||||
|
diagnostics, development servers, production builds, and DevToolbar extensions.
|
||||||
|
|
||||||
|
Use `definePlugin()` and declare `enforce`, `before`, or `after` when ordering matters.
|
||||||
|
Duplicate names and dependency cycles are rejected.
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "@wrnexus/plugin",
|
||||||
|
"version": "0.3.6",
|
||||||
|
"type": "module",
|
||||||
|
"description": "@wrnexus/plugin — part of the WrNexus framework.",
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"module": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"engines": {
|
||||||
|
"bun": ">=1.3.0"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
"access": "restricted"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"import": "./dist/index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@wrnexus/syntax": "^0.3.6"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/pubsub",
|
"name": "@wrnexus/pubsub",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/pubsub — part of the WrNexus framework.",
|
"description": "@wrnexus/pubsub — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/queue",
|
"name": "@wrnexus/queue",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/queue — part of the WrNexus framework.",
|
"description": "@wrnexus/queue — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/reactive",
|
"name": "@wrnexus/reactive",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/reactive — part of the WrNexus framework.",
|
"description": "@wrnexus/reactive — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/router",
|
"name": "@wrnexus/router",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/router — part of the WrNexus framework.",
|
"description": "@wrnexus/router — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
@@ -21,8 +21,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/compiler": "^0.2.31",
|
"@wrnexus/compiler": "^0.3.6",
|
||||||
"@wrnexus/core": "^0.2.31"
|
"@wrnexus/core": "^0.3.6"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/ssr",
|
"name": "@wrnexus/ssr",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/ssr — part of the WrNexus framework.",
|
"description": "@wrnexus/ssr — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/core": "^0.2.31"
|
"@wrnexus/core": "^0.3.6"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ Tokens are emitted as `--wire-<key>` custom properties, **except** the reserved
|
|||||||
type ThemeTokens = Record<string, string>;
|
type ThemeTokens = Record<string, string>;
|
||||||
|
|
||||||
interface ThemeConfig {
|
interface ThemeConfig {
|
||||||
|
palette?: ThemePaletteName | CustomThemePalette;
|
||||||
default?: string; // theme used when no cookie is present
|
default?: string; // theme used when no cookie is present
|
||||||
themes?: Record<string, ThemeTokens>; // deep-merged over built-in light/dark
|
themes?: Record<string, ThemeTokens>; // deep-merged over built-in light/dark
|
||||||
}
|
}
|
||||||
@@ -117,7 +118,30 @@ interface ResolvedTheme {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Built-in token keys (both `light` and `dark`): `color-scheme`, `color-bg`, `color-surface`, `color-surface-2`, `color-text`, `color-muted`, `color-border`, `color-primary`, `color-primary-hover`, `color-primary-contrast`, `color-danger`, `color-success`, `color-warning`, `radius`, `radius-sm`, `font-sans`, `shadow-1`.
|
Built-in palettes are `blue`, `indigo`, `violet`, `emerald`, `cyan`, `rose`,
|
||||||
|
`amber`, and `slate`. Each supplies primary, secondary, info, success, warning,
|
||||||
|
danger/error, hover, and contrast colors to every light/dark theme. Built-in
|
||||||
|
token keys also include surfaces, text, borders, radii, fonts, and shadows.
|
||||||
|
|
||||||
|
A custom palette is intentionally complete, so components never fall back to an
|
||||||
|
unrelated blue status or action color:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
theme: {
|
||||||
|
palette: {
|
||||||
|
primary: "#7c3aed",
|
||||||
|
primaryHover: "#6d28d9",
|
||||||
|
primaryContrast: "#ffffff",
|
||||||
|
secondary: "#db2777",
|
||||||
|
secondaryHover: "#be185d",
|
||||||
|
secondaryContrast: "#ffffff",
|
||||||
|
info: "#2563eb",
|
||||||
|
success: "#059669",
|
||||||
|
warning: "#d97706",
|
||||||
|
danger: "#dc2626",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
The client runtime (`renderThemeRuntime`) exposes `window.wireTheme` with `{ get, set, toggle, bind, themes }`, wires up any `[data-wire-theme-toggle]` and `[data-wire-theme-set]` elements on load, and persists the choice to the `wire-theme` cookie (`max-age` 1 year, `samesite=lax`). `toggle()` cycles through the configured theme names in order.
|
The client runtime (`renderThemeRuntime`) exposes `window.wireTheme` with `{ get, set, toggle, bind, themes }`, wires up any `[data-wire-theme-toggle]` and `[data-wire-theme-set]` elements on load, and persists the choice to the `wire-theme` cookie (`max-age` 1 year, `samesite=lax`). `toggle()` cycles through the configured theme names in order.
|
||||||
|
|
||||||
@@ -135,6 +159,7 @@ export default {
|
|||||||
port: 3000,
|
port: 3000,
|
||||||
db: { driver: "sqlite", url: "app.db" },
|
db: { driver: "sqlite", url: "app.db" },
|
||||||
theme: {
|
theme: {
|
||||||
|
palette: "violet",
|
||||||
default: "dark",
|
default: "dark",
|
||||||
themes: {
|
themes: {
|
||||||
light: { "color-primary": "#7c3aed" }, // override one token; rest inherited
|
light: { "color-primary": "#7c3aed" }, // override one token; rest inherited
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/styles",
|
"name": "@wrnexus/styles",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/styles — part of the WrNexus framework.",
|
"description": "@wrnexus/styles — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
@@ -21,7 +21,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/uploader": "^0.2.31"
|
"@wrnexus/uploader": "^0.3.6",
|
||||||
|
"@wrnexus/core": "^0.3.6",
|
||||||
|
"@wrnexus/plugin": "^0.3.6"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# @wrnexus/syntax
|
||||||
|
|
||||||
|
Canonical WRN lexer, parser, AST, language metadata, source positions, and stable
|
||||||
|
diagnostics. Framework tooling should import this package instead of implementing a
|
||||||
|
separate `.wrn` parser.
|
||||||
|
|
||||||
|
See `docs/WRN-LANGUAGE-SPEC-1.0.md` in the WRNexusJS repository.
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"name": "@wrnexus/syntax",
|
||||||
|
"version": "0.3.6",
|
||||||
|
"type": "module",
|
||||||
|
"description": "@wrnexus/syntax — part of the WrNexus framework.",
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"module": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"engines": {
|
||||||
|
"bun": ">=1.3.0"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
"access": "restricted"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"import": "./dist/index.js"
|
||||||
|
},
|
||||||
|
"./parser": {
|
||||||
|
"types": "./dist/parser.d.ts",
|
||||||
|
"import": "./dist/parser.js"
|
||||||
|
},
|
||||||
|
"./tokenizer": {
|
||||||
|
"types": "./dist/tokenizer.d.ts",
|
||||||
|
"import": "./dist/tokenizer.js"
|
||||||
|
},
|
||||||
|
"./types": {
|
||||||
|
"types": "./dist/types.d.ts",
|
||||||
|
"import": "./dist/types.js"
|
||||||
|
},
|
||||||
|
"./diagnostics": {
|
||||||
|
"types": "./dist/diagnostics.d.ts",
|
||||||
|
"import": "./dist/diagnostics.js"
|
||||||
|
},
|
||||||
|
"./spec": {
|
||||||
|
"types": "./dist/spec.d.ts",
|
||||||
|
"import": "./dist/spec.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/test",
|
"name": "@wrnexus/test",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/test — part of the WrNexus framework.",
|
"description": "@wrnexus/test — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/tracking",
|
"name": "@wrnexus/tracking",
|
||||||
"version": "0.2.31",
|
"version": "0.3.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "@wrnexus/tracking — part of the WrNexus framework.",
|
"description": "@wrnexus/tracking — part of the WrNexus framework.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"module": "./dist/index.js",
|
"module": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"engines": {
|
"engines": {
|
||||||
"bun": ">=1.1.0"
|
"bun": ">=1.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"registry": "https://registry.npmjs.org/",
|
"registry": "https://registry.npmjs.org/",
|
||||||
|
|||||||
@@ -0,0 +1,784 @@
|
|||||||
|
# WRNexus UI component reference
|
||||||
|
|
||||||
|
This reference is generated from the 85 packaged `.wrn` component sources. Props marked required have no default; all others show their runtime default.
|
||||||
|
|
||||||
|
## Advanced-forms
|
||||||
|
|
||||||
|
### AdvancedSelect
|
||||||
|
|
||||||
|
Theme-aware, responsive advanced select component.
|
||||||
|
|
||||||
|
- Mount: `data-component="AdvancedSelect"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Advanced Select"`, `name: string = ""`, `value: string = ""`, `values: string = []`, `options: string = []`, `groups: string = []`, `placeholder: string = "Select an option"`, `placeholderIcon: string = ""`, `searchPlaceholder: string = "Search options…"`, `multiple: boolean = false`, `searchable: boolean = true`, `defaultOpen: boolean = false`, `clearable: boolean = true`, `allowEmpty: boolean = true`, `tags: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `invalid: boolean = false`, `validationMessage: string = ""`, `helpText: string = ""`, `loading: boolean = false`, `loadingLabel: string = "Loading options…"`, `emptyLabel: string = "No options found"`, `selectedOptionsLabel: string = "Selected options"`, `clearLabel: string = "Clear selection"`, `createLabel: string = "Create"`, `loadMoreLabel: string = "Load more"`, `searchMode: string = "contains"`, `searchFields: string = "label,description"`, `minSearchLength: number = 0`, `searchResultLimit: number = 0`, `maxSelections: number = 0`, `showCounter: boolean = false`, `counterTemplate: string = "{selected} selected"`, `optionTemplate: string = "default"`, `selectedTemplate: string = "default"`, `closeOnSelect: boolean = true`, `scrollToSelected: boolean = true`, `fixed: boolean = false`, `placement: string = "bottom"`, `remote: boolean = false`, `remoteUrl: string = ""`, `remoteQueryParam: string = "q"`, `remoteDebounce: number = 250`, `remoteAutoLoad: boolean = true`, `infinite: boolean = false`, `hasMore: boolean = false`, `page: number = 1`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: `search`, `select`, `change`, `clear`, `open`, `close`, `load`, `error`
|
||||||
|
|
||||||
|
### ComboBox
|
||||||
|
|
||||||
|
Editable autocomplete combobox with local and remote suggestions.
|
||||||
|
|
||||||
|
- Mount: `data-component="ComboBox"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "ComboBox"`, `name: string = ""`, `value: string = ""`, `options: string = []`, `groups: string = []`, `placeholder: string = "Search or select an option"`, `searchPlaceholder: string = "Start typing…"`, `clearable: boolean = true`, `allowCustomValue: boolean = false`, `disabled: boolean = false`, `required: boolean = false`, `invalid: boolean = false`, `validationMessage: string = ""`, `helpText: string = ""`, `loading: boolean = false`, `loadingLabel: string = "Loading suggestions…"`, `emptyLabel: string = "No matching options"`, `clearLabel: string = "Clear value"`, `toggleLabel: string = "Toggle suggestions"`, `searchMode: string = "contains"`, `searchFields: string = "label,description"`, `minSearchLength: number = 0`, `searchResultLimit: number = 0`, `optionTemplate: string = "default"`, `defaultOpen: boolean = false`, `closeOnSelect: boolean = true`, `fixed: boolean = false`, `placement: string = "bottom"`, `autocomplete: string = "off"`, `remote: boolean = false`, `remoteUrl: string = ""`, `remoteQueryParam: string = "q"`, `remoteDebounce: number = 250`, `remoteAutoLoad: boolean = true`, `infinite: boolean = false`, `hasMore: boolean = false`, `page: number = 1`, `loadMoreLabel: string = "Load more"`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: `search`, `select`, `change`, `clear`, `open`, `close`, `load`, `error`
|
||||||
|
|
||||||
|
### 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
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### InputNumber
|
||||||
|
|
||||||
|
Theme-aware, responsive input number component.
|
||||||
|
|
||||||
|
- Mount: `data-component="InputNumber"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Input Number"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "number"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### PinInput
|
||||||
|
|
||||||
|
Secure multi-cell PIN and verification-code input with regex and paste support.
|
||||||
|
|
||||||
|
- Mount: `data-component="PinInput"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Verification code"`, `name: string = "pin"`, `value: string = ""`, `length: number = 4`, `pattern: string = "[0-9]"`, `type: string = "text"`, `inputMode: string = "numeric"`, `placeholder: string = "○"`, `autocomplete: string = "one-time-code"`, `masked: boolean = false`, `disabled: boolean = false`, `readonly: boolean = false`, `required: boolean = false`, `autoFocus: boolean = false`, `autoSubmit: boolean = false`, `allowPaste: boolean = true`, `clearable: boolean = true`, `clearLabel: string = "Clear code"`, `separator: string = ""`, `groupSize: number = 0`, `helpText: string = ""`, `invalid: boolean = false`, `validationMessage: string = ""`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: `input`, `change`, `complete`, `paste`, `clear`, `error`
|
||||||
|
|
||||||
|
### SearchBox
|
||||||
|
|
||||||
|
Theme-aware, responsive search box component.
|
||||||
|
|
||||||
|
- Mount: `data-component="SearchBox"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Search Box"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "search"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### StrongPassword
|
||||||
|
|
||||||
|
Theme-aware, responsive strong password component.
|
||||||
|
|
||||||
|
- Mount: `data-component="StrongPassword"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Password"`, `name: string = "password"`, `value: string = ""`, `placeholder: string = "Create a strong password"`, `autocomplete: string = "new-password"`, `minLength: number = 8`, `specialCharactersSet: string = "!@#$%^&*()_+-=[]{}|;:,.<>?"`, `requireLowercase: boolean = true`, `requireUppercase: boolean = true`, `requireNumber: boolean = true`, `requireSpecialCharacter: boolean = true`, `showRequirements: boolean = true`, `presentation: string = "inline"`, `hintText: string = "Use a unique password you do not use elsewhere."`, `emptyLabel: string = "Enter a password"`, `weakLabel: string = "Weak"`, `fairLabel: string = "Fair"`, `goodLabel: string = "Good"`, `strongLabel: string = "Strong"`, `disabled: boolean = false`, `readonly: boolean = false`, `required: boolean = false`, `invalid: boolean = false`, `validationMessage: string = ""`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: `input`, `change`, `strength`
|
||||||
|
|
||||||
|
### ToggleCount
|
||||||
|
|
||||||
|
Theme-aware, responsive toggle count component.
|
||||||
|
|
||||||
|
- Mount: `data-component="ToggleCount"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Toggle Count"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "text"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### TogglePassword
|
||||||
|
|
||||||
|
Accessible password field with optional show and hide controls.
|
||||||
|
|
||||||
|
- Mount: `data-component="TogglePassword"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Password"`, `name: string = "password"`, `value: string = ""`, `placeholder: string = "Enter your password"`, `autocomplete: string = "current-password"`, `minlength: string = ""`, `maxlength: string = ""`, `pattern: string = "(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9]).{8,}"`, `fields: string = []`, `visible: boolean = false`, `toggleable: boolean = true`, `toggleMode: string = "button"`, `checkboxLabel: string = "Show password"`, `showLabel: string = "Show password"`, `hideLabel: string = "Hide password"`, `disabled: boolean = false`, `readonly: boolean = false`, `required: boolean = false`, `invalid: boolean = false`, `helpText: string = ""`, `validationMessage: string = ""`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: `input`, `change`, `toggle`
|
||||||
|
|
||||||
|
## Base
|
||||||
|
|
||||||
|
### Accordion
|
||||||
|
|
||||||
|
Theme-aware, responsive accordion component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Accordion"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `items: string = []`, `multiple: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Alert
|
||||||
|
|
||||||
|
Theme-aware, responsive alert component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Alert"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Alert"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Avatar
|
||||||
|
|
||||||
|
Theme-aware, responsive avatar component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Avatar"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Avatar"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### AvatarGroup
|
||||||
|
|
||||||
|
Theme-aware, responsive avatar group component.
|
||||||
|
|
||||||
|
- Mount: `data-component="AvatarGroup"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Avatar Group"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Badge
|
||||||
|
|
||||||
|
Theme-aware, responsive badge component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Badge"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Badge"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Blockquote
|
||||||
|
|
||||||
|
Theme-aware, responsive blockquote component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Blockquote"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Blockquote"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Button
|
||||||
|
|
||||||
|
Theme-aware, responsive button component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Button"`
|
||||||
|
- Props: `label: string = "Button"`, `loadingLabel: string = "Loading…"`, `description: string = ""`, `as: string = ""`, `href: string = ""`, `target: string = ""`, `rel: string = ""`, `type: string = "button"`, `variant: string = "default"`, `color: string = "primary"`, `size: string = "default"`, `disabled: boolean = false`, `loading: boolean = false`, `pill: boolean = false`, `fullWidth: boolean = false`, `icon: string = ""`, `iconPosition: string = "start"`, `ariaLabel: string = ""`, `ariaPressed: string = ""`, `ariaExpanded: string = ""`, `ariaControls: string = ""`, `title: string = ""`, `autofocus: boolean = false`, `controlClass: string = ""`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### ButtonGroup
|
||||||
|
|
||||||
|
Theme-aware, responsive button group component.
|
||||||
|
|
||||||
|
- Mount: `data-component="ButtonGroup"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Button Group"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Card
|
||||||
|
|
||||||
|
Theme-aware, responsive card component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Card"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Card"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Carousel
|
||||||
|
|
||||||
|
Theme-aware, responsive carousel component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Carousel"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Carousel"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### ChatBubble
|
||||||
|
|
||||||
|
Theme-aware, responsive chat bubble component.
|
||||||
|
|
||||||
|
- Mount: `data-component="ChatBubble"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Chat Bubble"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Collapse
|
||||||
|
|
||||||
|
Theme-aware, responsive collapse component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Collapse"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `items: string = []`, `multiple: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### DatePicker
|
||||||
|
|
||||||
|
Theme-aware, responsive date picker component.
|
||||||
|
|
||||||
|
- Mount: `data-component="DatePicker"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Date Picker"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "date"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### DeviceFrame
|
||||||
|
|
||||||
|
Theme-aware, responsive device frame component.
|
||||||
|
|
||||||
|
- Mount: `data-component="DeviceFrame"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Device Frame"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### FileUploadProgress
|
||||||
|
|
||||||
|
Theme-aware, responsive file upload progress component.
|
||||||
|
|
||||||
|
- Mount: `data-component="FileUploadProgress"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Progress"`, `value: number = 50`, `max: number = 100`, `showValue: boolean = true`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### LegendIndicator
|
||||||
|
|
||||||
|
Theme-aware, responsive legend indicator component.
|
||||||
|
|
||||||
|
- Mount: `data-component="LegendIndicator"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Legend Indicator"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### List
|
||||||
|
|
||||||
|
Theme-aware, responsive list component.
|
||||||
|
|
||||||
|
- Mount: `data-component="List"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "List"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### ListGroup
|
||||||
|
|
||||||
|
Theme-aware, responsive list group component.
|
||||||
|
|
||||||
|
- Mount: `data-component="ListGroup"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "List Group"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Marquee
|
||||||
|
|
||||||
|
Theme-aware, responsive marquee component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Marquee"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Marquee"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Progress
|
||||||
|
|
||||||
|
Theme-aware, responsive progress component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Progress"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Progress"`, `value: number = 50`, `max: number = 100`, `showValue: boolean = true`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Rating
|
||||||
|
|
||||||
|
Theme-aware, responsive rating component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Rating"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Rating"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Skeleton
|
||||||
|
|
||||||
|
Theme-aware, responsive skeleton component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Skeleton"`
|
||||||
|
- Props: `color: string = "primary"`, `label: string = "Loading"`, `size: string = "md"`, `lines: number = 3`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Spinner
|
||||||
|
|
||||||
|
Theme-aware, responsive spinner component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Spinner"`
|
||||||
|
- Props: `color: string = "primary"`, `label: string = "Loading"`, `size: string = "md"`, `lines: number = 3`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### StyledIcon
|
||||||
|
|
||||||
|
Theme-aware, responsive styled icon component.
|
||||||
|
|
||||||
|
- Mount: `data-component="StyledIcon"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Styled Icon"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Timeline
|
||||||
|
|
||||||
|
Theme-aware, responsive timeline component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Timeline"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Timeline"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Toast
|
||||||
|
|
||||||
|
Theme-aware, responsive toast component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Toast"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Toast"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### TreeView
|
||||||
|
|
||||||
|
Theme-aware, responsive tree view component.
|
||||||
|
|
||||||
|
- Mount: `data-component="TreeView"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Tree View"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
## Forms
|
||||||
|
|
||||||
|
### Checkbox
|
||||||
|
|
||||||
|
Theme-aware, responsive checkbox component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Checkbox"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Checkbox"`, `name: string = ""`, `value: string = "on"`, `checked: boolean = false`, `disabled: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### ColorPicker
|
||||||
|
|
||||||
|
Theme-aware, responsive color picker component.
|
||||||
|
|
||||||
|
- Mount: `data-component="ColorPicker"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Color Picker"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "color"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### FileInput
|
||||||
|
|
||||||
|
Theme-aware, responsive file input component.
|
||||||
|
|
||||||
|
- Mount: `data-component="FileInput"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "File Input"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "file"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Input
|
||||||
|
|
||||||
|
Theme-aware, responsive input component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Input"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Input"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "text"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### InputGroup
|
||||||
|
|
||||||
|
Theme-aware, responsive input group component.
|
||||||
|
|
||||||
|
- Mount: `data-component="InputGroup"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Input Group"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "text"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Radio
|
||||||
|
|
||||||
|
Theme-aware, responsive radio component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Radio"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Radio"`, `name: string = ""`, `value: string = "on"`, `checked: boolean = false`, `disabled: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### RangeSlider
|
||||||
|
|
||||||
|
Theme-aware, responsive range slider component.
|
||||||
|
|
||||||
|
- Mount: `data-component="RangeSlider"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Range Slider"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "range"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Select
|
||||||
|
|
||||||
|
Theme-aware, responsive select component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Select"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Select"`, `name: string = ""`, `value: string = ""`, `options: string = []`, `placeholder: string = "Select an option"`, `multiple: boolean = false`, `disabled: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Switch
|
||||||
|
|
||||||
|
Theme-aware, responsive switch component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Switch"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Switch"`, `name: string = ""`, `value: string = "on"`, `checked: boolean = false`, `disabled: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Textarea
|
||||||
|
|
||||||
|
Theme-aware, responsive textarea component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Textarea"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Textarea"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `rows: number = 5`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### TimePicker
|
||||||
|
|
||||||
|
Theme-aware, responsive time picker component.
|
||||||
|
|
||||||
|
- Mount: `data-component="TimePicker"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Time Picker"`, `name: string = ""`, `value: string = ""`, `placeholder: string = ""`, `type: string = "time"`, `min: string = ""`, `max: string = ""`, `step: string = ""`, `disabled: boolean = false`, `required: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
## 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: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### 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: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Chart
|
||||||
|
|
||||||
|
Theme-aware, responsive chart component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Chart"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Chart"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Clipboard
|
||||||
|
|
||||||
|
Theme-aware, responsive clipboard component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Clipboard"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Clipboard"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Confetti
|
||||||
|
|
||||||
|
Theme-aware, responsive confetti component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Confetti"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Confetti"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### DataMap
|
||||||
|
|
||||||
|
Theme-aware, responsive data map component.
|
||||||
|
|
||||||
|
- Mount: `data-component="DataMap"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Data Map"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### DataTable
|
||||||
|
|
||||||
|
Theme-aware, responsive data table component.
|
||||||
|
|
||||||
|
- Mount: `data-component="DataTable"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `caption: string = "Data Table"`, `columns: string = []`, `rows: string = []`, `striped: boolean = true`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### DragAndDrop
|
||||||
|
|
||||||
|
Theme-aware, responsive drag and drop component.
|
||||||
|
|
||||||
|
- Mount: `data-component="DragAndDrop"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Drag And Drop"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### 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: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Map
|
||||||
|
|
||||||
|
Theme-aware, responsive map component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Map"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Map"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### 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: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### WysiwygEditor
|
||||||
|
|
||||||
|
Theme-aware, responsive wysiwyg editor component.
|
||||||
|
|
||||||
|
- Mount: `data-component="WysiwygEditor"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Wysiwyg Editor"`, `description: string = ""`, `items: string = []`, `variant: string = "default"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
### Columns
|
||||||
|
|
||||||
|
Theme-aware, responsive columns component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Columns"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `columns: number = 2`, `gap: string = "md"`, `maxWidth: string = "xl"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Container
|
||||||
|
|
||||||
|
Theme-aware, responsive container component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Container"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `columns: number = 2`, `gap: string = "md"`, `maxWidth: string = "xl"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### CustomScrollbar
|
||||||
|
|
||||||
|
Theme-aware, responsive custom scrollbar component.
|
||||||
|
|
||||||
|
- Mount: `data-component="CustomScrollbar"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `columns: number = 2`, `gap: string = "md"`, `maxWidth: string = "xl"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Divider
|
||||||
|
|
||||||
|
Theme-aware, responsive divider component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Divider"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
|
||||||
|
- Slots: None
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Grid
|
||||||
|
|
||||||
|
Theme-aware, responsive grid component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Grid"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `columns: number = 2`, `gap: string = "md"`, `maxWidth: string = "xl"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Image
|
||||||
|
|
||||||
|
Theme-aware, responsive image component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Image"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `src: string = ""`, `alt: string = ""`, `width: string = ""`, `height: string = ""`, `loading: string = "lazy"`, `rounded: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Kbd
|
||||||
|
|
||||||
|
Theme-aware, responsive kbd component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Kbd"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "⌘ K"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### LayoutSplitter
|
||||||
|
|
||||||
|
Theme-aware, responsive layout splitter component.
|
||||||
|
|
||||||
|
- Mount: `data-component="LayoutSplitter"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `columns: number = 2`, `gap: string = "md"`, `maxWidth: string = "xl"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Link
|
||||||
|
|
||||||
|
Theme-aware, responsive link component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Link"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Link"`, `href: string = "#"`, `target: string = ""`, `rel: string = ""`, `external: boolean = false`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Typography
|
||||||
|
|
||||||
|
Theme-aware, responsive typography component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Typography"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `columns: number = 2`, `gap: string = "md"`, `maxWidth: string = "xl"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
## Navigation
|
||||||
|
|
||||||
|
### Breadcrumb
|
||||||
|
|
||||||
|
Theme-aware, responsive breadcrumb component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Breadcrumb"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Breadcrumb"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### MegaMenu
|
||||||
|
|
||||||
|
Theme-aware, responsive mega menu component.
|
||||||
|
|
||||||
|
- Mount: `data-component="MegaMenu"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Mega Menu"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Nav
|
||||||
|
|
||||||
|
Theme-aware, responsive nav component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Nav"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Nav"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Navbar
|
||||||
|
|
||||||
|
Theme-aware, responsive navbar component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Navbar"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Navbar"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Pagination
|
||||||
|
|
||||||
|
Theme-aware, responsive pagination component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Pagination"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Pagination"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Scrollspy
|
||||||
|
|
||||||
|
Theme-aware, responsive scrollspy component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Scrollspy"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Scrollspy"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Sidebar
|
||||||
|
|
||||||
|
Theme-aware, responsive sidebar component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Sidebar"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Sidebar"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Stepper
|
||||||
|
|
||||||
|
Theme-aware, responsive stepper component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Stepper"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Stepper"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Tabs
|
||||||
|
|
||||||
|
Theme-aware, responsive tabs component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Tabs"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `label: string = "Tabs"`, `items: string = []`, `active: string = ""`, `orientation: string = "horizontal"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
## Overlays
|
||||||
|
|
||||||
|
### ContextMenu
|
||||||
|
|
||||||
|
Theme-aware, responsive context menu component.
|
||||||
|
|
||||||
|
- Mount: `data-component="ContextMenu"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Context Menu"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Drawer
|
||||||
|
|
||||||
|
Theme-aware, responsive drawer component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Drawer"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Drawer"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Dropdown
|
||||||
|
|
||||||
|
Theme-aware, responsive dropdown component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Dropdown"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Dropdown"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Modal
|
||||||
|
|
||||||
|
Theme-aware, responsive modal component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Modal"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Modal"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Popover
|
||||||
|
|
||||||
|
Theme-aware, responsive popover component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Popover"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Popover"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
### Tooltip
|
||||||
|
|
||||||
|
Theme-aware, responsive tooltip component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Tooltip"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `title: string = "Tooltip"`, `description: string = ""`, `open: boolean = false`, `placement: string = "bottom"`, `closeLabel: string = "Close"`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
|
|
||||||
|
## Tables
|
||||||
|
|
||||||
|
### Table
|
||||||
|
|
||||||
|
Theme-aware, responsive table component.
|
||||||
|
|
||||||
|
- Mount: `data-component="Table"`
|
||||||
|
- Props: `size: string = "default"`, `color: string = "primary"`, `caption: string = "Table"`, `columns: string = []`, `rows: string = []`, `striped: boolean = true`, `class: string = ""`
|
||||||
|
- Slots: `default`
|
||||||
|
- Events: None
|
||||||
+67
-1
@@ -15,6 +15,11 @@ driven by `var(--wire-*)` theme tokens, so components restyle instantly when the
|
|||||||
theme changes. The tiny JS surface (`src/index.ts`) exists only so the toolchain
|
theme changes. The tiny JS surface (`src/index.ts`) exists only so the toolchain
|
||||||
(CLI build + dev server) can locate the component directory and stylesheet.
|
(CLI build + dev server) can locate the component directory and stylesheet.
|
||||||
|
|
||||||
|
The complete PDF-aligned catalog currently contains **891 components**. The
|
||||||
|
generated `COMPONENTS.md` and `component-reference.json` files document every
|
||||||
|
mount name, prop, inferred type, default/required status, slot, event, category,
|
||||||
|
and source file directly from the packaged `.wrn` source.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -65,11 +70,25 @@ body from either a named prop or the default slot.
|
|||||||
### Additional controls & data display
|
### Additional controls & data display
|
||||||
|
|
||||||
Also shipped: `select`, `radio`, `switch`, `progress`, `tag`, `skeleton`,
|
Also shipped: `select`, `radio`, `switch`, `progress`, `tag`, `skeleton`,
|
||||||
`tooltip`, and `table`.
|
`tooltip`, `table`, `FAQAccordion`, `AnnouncementBar`, and `BackToTop`.
|
||||||
|
|
||||||
|
The PDF-defined minimum release and essential build-first set also includes
|
||||||
|
typed typography, form primitives, loading actions, combobox and multi-select,
|
||||||
|
time/date-time and recurring schedule controls, confirmation dialogs, data
|
||||||
|
tables, filters, desktop/mobile navigation, mega menus, marketing/product/legal
|
||||||
|
page shells, product and metric cards, FAQ composition, pricing comparison,
|
||||||
|
SDK tabs, legal navigation, and cookie preferences.
|
||||||
|
|
||||||
|
`Seo` and `StructuredData` remain framework/page concerns rather than body
|
||||||
|
components: use the native page `seo { ... }` block and document-head APIs so
|
||||||
|
metadata is emitted in `<head>` instead of invalid component markup.
|
||||||
|
|
||||||
The authoritative, always-current list is `uiComponentNames()` (below), which reads
|
The authoritative, always-current list is `uiComponentNames()` (below), which reads
|
||||||
the component directory at runtime.
|
the component directory at runtime.
|
||||||
|
|
||||||
|
For the full catalog, see [`COMPONENTS.md`](./COMPONENTS.md). The machine-readable
|
||||||
|
equivalent is exported as `@wrnexus/ui/component-reference.json`.
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
The JS module (`@wrnexus/ui`) exposes four helpers used by the build tooling to
|
The JS module (`@wrnexus/ui`) exposes four helpers used by the build tooling to
|
||||||
@@ -97,6 +116,53 @@ 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
|
||||||
|
|
||||||
|
Components use static Tailwind utility classes alongside the shared `.wire-*`
|
||||||
|
layer. If the package is consumed by a separate Tailwind build, include its
|
||||||
|
component sources so every utility is generated:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import "tailwindcss";
|
||||||
|
@source "../node_modules/@wrnexus/ui/components/*.wrn";
|
||||||
|
```
|
||||||
|
|
||||||
|
The shared stylesheet gives all component boundaries consistent, GPU-friendly
|
||||||
|
entry and interaction motion. Override `--wire-motion-fast`,
|
||||||
|
`--wire-motion-base`, `--wire-motion-slow`, `--wire-ease-standard`, or
|
||||||
|
`--wire-ease-emphasized` to tune it. Hover lift is limited to precise pointing
|
||||||
|
devices and `prefers-reduced-motion` is honored automatically.
|
||||||
|
|
||||||
|
### Using the selected theme in application UI
|
||||||
|
|
||||||
|
The active theme and palette are not limited to `@wrnexus/ui` components. The
|
||||||
|
framework exposes the resolved values as semantic CSS custom properties, so
|
||||||
|
pages and custom `.wrn` components can use the same contract:
|
||||||
|
|
||||||
|
```css
|
||||||
|
.account-card {
|
||||||
|
background: var(--wire-color-surface);
|
||||||
|
color: var(--wire-color-text);
|
||||||
|
border: 1px solid var(--wire-color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-card__action {
|
||||||
|
background: var(--wire-color-primary);
|
||||||
|
color: var(--wire-color-primary-contrast);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Stable no-spacing helper classes are also available: `wire-bg-page`,
|
||||||
|
`wire-bg-surface`, `wire-bg-surface-2`, `wire-bg-primary`, `wire-bg-secondary`,
|
||||||
|
`wire-text`, `wire-text-muted`, `wire-text-primary`, `wire-text-success`,
|
||||||
|
`wire-text-warning`, `wire-text-danger`, and `wire-border`.
|
||||||
|
|
||||||
|
Tailwind-authored custom markup can continue using the palette families already
|
||||||
|
used by packaged components. `indigo-*` and `violet-*` resolve to primary,
|
||||||
|
`blue-*` to info, `emerald-*`/`green-*` to success, `amber-*` to warning, and
|
||||||
|
`red-*`/`rose-*` to danger. These aliases live at `:root`, so they work outside
|
||||||
|
a `[data-component]` boundary too.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Auto-discovery
|
### Auto-discovery
|
||||||
|
|||||||
@@ -0,0 +1,434 @@
|
|||||||
|
{
|
||||||
|
"sourceDocuments": ["Screenshot-directed WRNexus UI catalog reset"],
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"name": "Container",
|
||||||
|
"category": "layout",
|
||||||
|
"purpose": "Theme-aware, responsive container component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Columns",
|
||||||
|
"category": "layout",
|
||||||
|
"purpose": "Theme-aware, responsive columns component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Grid",
|
||||||
|
"category": "layout",
|
||||||
|
"purpose": "Theme-aware, responsive grid component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LayoutSplitter",
|
||||||
|
"category": "layout",
|
||||||
|
"purpose": "Theme-aware, responsive layout splitter component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Typography",
|
||||||
|
"category": "layout",
|
||||||
|
"purpose": "Theme-aware, responsive typography component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Image",
|
||||||
|
"category": "layout",
|
||||||
|
"purpose": "Theme-aware, responsive image component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Link",
|
||||||
|
"category": "layout",
|
||||||
|
"purpose": "Theme-aware, responsive link component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Divider",
|
||||||
|
"category": "layout",
|
||||||
|
"purpose": "Theme-aware, responsive divider component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Kbd",
|
||||||
|
"category": "layout",
|
||||||
|
"purpose": "Theme-aware, responsive kbd component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CustomScrollbar",
|
||||||
|
"category": "layout",
|
||||||
|
"purpose": "Theme-aware, responsive custom scrollbar component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Accordion",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive accordion component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Alert",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive alert component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Avatar",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive avatar component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "AvatarGroup",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive avatar group component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Badge",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive badge component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Blockquote",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive blockquote component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Button",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive button component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ButtonGroup",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive button group component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Card",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive card component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ChatBubble",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive chat bubble component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Carousel",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive carousel component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Collapse",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive collapse component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DatePicker",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive date picker component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DeviceFrame",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive device frame component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "List",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive list component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ListGroup",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive list group component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LegendIndicator",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive legend indicator component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Progress",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive progress component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "FileUploadProgress",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive file upload progress component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rating",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive rating component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Skeleton",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive skeleton component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Spinner",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive spinner component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "StyledIcon",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive styled icon component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Toast",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive toast component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Timeline",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive timeline component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TreeView",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive tree view component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Marquee",
|
||||||
|
"category": "base",
|
||||||
|
"purpose": "Theme-aware, responsive marquee component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Navbar",
|
||||||
|
"category": "navigation",
|
||||||
|
"purpose": "Theme-aware, responsive navbar component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "MegaMenu",
|
||||||
|
"category": "navigation",
|
||||||
|
"purpose": "Theme-aware, responsive mega menu component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nav",
|
||||||
|
"category": "navigation",
|
||||||
|
"purpose": "Theme-aware, responsive nav component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tabs",
|
||||||
|
"category": "navigation",
|
||||||
|
"purpose": "Theme-aware, responsive tabs component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sidebar",
|
||||||
|
"category": "navigation",
|
||||||
|
"purpose": "Theme-aware, responsive sidebar component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Scrollspy",
|
||||||
|
"category": "navigation",
|
||||||
|
"purpose": "Theme-aware, responsive scrollspy component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Breadcrumb",
|
||||||
|
"category": "navigation",
|
||||||
|
"purpose": "Theme-aware, responsive breadcrumb component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pagination",
|
||||||
|
"category": "navigation",
|
||||||
|
"purpose": "Theme-aware, responsive pagination component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Stepper",
|
||||||
|
"category": "navigation",
|
||||||
|
"purpose": "Theme-aware, responsive stepper component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Input",
|
||||||
|
"category": "forms",
|
||||||
|
"purpose": "Theme-aware, responsive input component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "InputGroup",
|
||||||
|
"category": "forms",
|
||||||
|
"purpose": "Theme-aware, responsive input group component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Textarea",
|
||||||
|
"category": "forms",
|
||||||
|
"purpose": "Theme-aware, responsive textarea component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "FileInput",
|
||||||
|
"category": "forms",
|
||||||
|
"purpose": "Theme-aware, responsive file input component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Checkbox",
|
||||||
|
"category": "forms",
|
||||||
|
"purpose": "Theme-aware, responsive checkbox component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Radio",
|
||||||
|
"category": "forms",
|
||||||
|
"purpose": "Theme-aware, responsive radio component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Switch",
|
||||||
|
"category": "forms",
|
||||||
|
"purpose": "Theme-aware, responsive switch component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Select",
|
||||||
|
"category": "forms",
|
||||||
|
"purpose": "Theme-aware, responsive select component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "RangeSlider",
|
||||||
|
"category": "forms",
|
||||||
|
"purpose": "Theme-aware, responsive range slider component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ColorPicker",
|
||||||
|
"category": "forms",
|
||||||
|
"purpose": "Theme-aware, responsive color picker component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TimePicker",
|
||||||
|
"category": "forms",
|
||||||
|
"purpose": "Theme-aware, responsive time picker component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "AdvancedSelect",
|
||||||
|
"category": "advanced-forms",
|
||||||
|
"purpose": "Theme-aware, responsive advanced select component.",
|
||||||
|
"events": ["search", "select", "change", "clear", "open", "close", "load", "error"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ComboBox",
|
||||||
|
"category": "advanced-forms",
|
||||||
|
"purpose": "Editable autocomplete combobox with local and remote suggestions.",
|
||||||
|
"events": ["search", "select", "change", "clear", "open", "close", "load", "error"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SearchBox",
|
||||||
|
"category": "advanced-forms",
|
||||||
|
"purpose": "Theme-aware, responsive search box component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "InputNumber",
|
||||||
|
"category": "advanced-forms",
|
||||||
|
"purpose": "Theme-aware, responsive input number component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "StrongPassword",
|
||||||
|
"category": "advanced-forms",
|
||||||
|
"purpose": "Theme-aware, responsive strong password component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TogglePassword",
|
||||||
|
"category": "advanced-forms",
|
||||||
|
"purpose": "Accessible password field with optional show and hide controls.",
|
||||||
|
"events": ["input", "change", "toggle"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ToggleCount",
|
||||||
|
"category": "advanced-forms",
|
||||||
|
"purpose": "Theme-aware, responsive toggle count component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CopyMarkup",
|
||||||
|
"category": "advanced-forms",
|
||||||
|
"purpose": "Theme-aware, responsive copy markup component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PinInput",
|
||||||
|
"category": "advanced-forms",
|
||||||
|
"purpose": "Secure multi-cell PIN and verification-code input with regex and paste support.",
|
||||||
|
"events": ["input", "change", "complete", "paste", "clear", "error"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dropdown",
|
||||||
|
"category": "overlays",
|
||||||
|
"purpose": "Theme-aware, responsive dropdown component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ContextMenu",
|
||||||
|
"category": "overlays",
|
||||||
|
"purpose": "Theme-aware, responsive context menu component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Modal",
|
||||||
|
"category": "overlays",
|
||||||
|
"purpose": "Theme-aware, responsive modal component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Drawer",
|
||||||
|
"category": "overlays",
|
||||||
|
"purpose": "Theme-aware, responsive drawer component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Popover",
|
||||||
|
"category": "overlays",
|
||||||
|
"purpose": "Theme-aware, responsive popover component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tooltip",
|
||||||
|
"category": "overlays",
|
||||||
|
"purpose": "Theme-aware, responsive tooltip component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Table",
|
||||||
|
"category": "tables",
|
||||||
|
"purpose": "Theme-aware, responsive table component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "AdvancedRangeSlider",
|
||||||
|
"category": "integrations",
|
||||||
|
"purpose": "Theme-aware, responsive advanced range slider component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "AdvancedDatePicker",
|
||||||
|
"category": "integrations",
|
||||||
|
"purpose": "Theme-aware, responsive advanced date picker component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Chart",
|
||||||
|
"category": "integrations",
|
||||||
|
"purpose": "Theme-aware, responsive chart component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Clipboard",
|
||||||
|
"category": "integrations",
|
||||||
|
"purpose": "Theme-aware, responsive clipboard component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Confetti",
|
||||||
|
"category": "integrations",
|
||||||
|
"purpose": "Theme-aware, responsive confetti component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DataMap",
|
||||||
|
"category": "integrations",
|
||||||
|
"purpose": "Theme-aware, responsive data map component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DataTable",
|
||||||
|
"category": "integrations",
|
||||||
|
"purpose": "Theme-aware, responsive data table component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DragAndDrop",
|
||||||
|
"category": "integrations",
|
||||||
|
"purpose": "Theme-aware, responsive drag and drop component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "FileUpload",
|
||||||
|
"category": "integrations",
|
||||||
|
"purpose": "Theme-aware, responsive file upload component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Map",
|
||||||
|
"category": "integrations",
|
||||||
|
"purpose": "Theme-aware, responsive map component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ToastNotifications",
|
||||||
|
"category": "integrations",
|
||||||
|
"purpose": "Theme-aware, responsive toast notifications component."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "WysiwygEditor",
|
||||||
|
"category": "integrations",
|
||||||
|
"purpose": "Theme-aware, responsive wysiwyg editor component."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"generatedFrom": "full component catalog reset",
|
||||||
|
"removedCount": 0,
|
||||||
|
"replacements": {}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
|||||||
|
component Accordion {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
items = []
|
||||||
|
multiple = false
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--accordion {class}">
|
||||||
|
{#each items as item}<details open="{item.open}"><summary>{item.label}</summary><div>{item.content}</div></details>{/each}
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component AdvancedDatePicker {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Advanced Date Picker"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component AdvancedRangeSlider {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Advanced Range Slider"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,456 @@
|
|||||||
|
component AdvancedSelect {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Advanced Select"
|
||||||
|
name = ""
|
||||||
|
value = ""
|
||||||
|
values = []
|
||||||
|
options = []
|
||||||
|
groups = []
|
||||||
|
placeholder = "Select an option"
|
||||||
|
placeholderIcon = ""
|
||||||
|
searchPlaceholder = "Search options…"
|
||||||
|
multiple = false
|
||||||
|
searchable = true
|
||||||
|
defaultOpen = false
|
||||||
|
clearable = true
|
||||||
|
allowEmpty = true
|
||||||
|
tags = false
|
||||||
|
disabled = false
|
||||||
|
required = false
|
||||||
|
invalid = false
|
||||||
|
validationMessage = ""
|
||||||
|
helpText = ""
|
||||||
|
loading = false
|
||||||
|
loadingLabel = "Loading options…"
|
||||||
|
emptyLabel = "No options found"
|
||||||
|
selectedOptionsLabel = "Selected options"
|
||||||
|
clearLabel = "Clear selection"
|
||||||
|
createLabel = "Create"
|
||||||
|
loadMoreLabel = "Load more"
|
||||||
|
searchMode = "contains"
|
||||||
|
searchFields = "label,description"
|
||||||
|
minSearchLength = 0
|
||||||
|
searchResultLimit = 0
|
||||||
|
maxSelections = 0
|
||||||
|
showCounter = false
|
||||||
|
counterTemplate = "{selected} selected"
|
||||||
|
optionTemplate = "default"
|
||||||
|
selectedTemplate = "default"
|
||||||
|
closeOnSelect = true
|
||||||
|
scrollToSelected = true
|
||||||
|
fixed = false
|
||||||
|
placement = "bottom"
|
||||||
|
remote = false
|
||||||
|
remoteUrl = ""
|
||||||
|
remoteQueryParam = "q"
|
||||||
|
remoteDebounce = 250
|
||||||
|
remoteAutoLoad = true
|
||||||
|
infinite = false
|
||||||
|
hasMore = false
|
||||||
|
page = 1
|
||||||
|
class = ""
|
||||||
|
@event search = function
|
||||||
|
@event select = function
|
||||||
|
@event change = function
|
||||||
|
@event clear = function
|
||||||
|
@event open = function
|
||||||
|
@event close = function
|
||||||
|
@event load = function
|
||||||
|
@event error = function
|
||||||
|
}
|
||||||
|
|
||||||
|
state open = defaultOpen
|
||||||
|
state query = ""
|
||||||
|
state activeIndex = -1
|
||||||
|
state selectedValue = value
|
||||||
|
state selectedValues = values
|
||||||
|
|
||||||
|
functions {
|
||||||
|
function allOptions() {
|
||||||
|
return [...groups.flatMap((group) => group.options || []), ...options]
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchableText(option) {
|
||||||
|
return ((option.label || "") + " " + (option.description || "")).toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
function matches(option) {
|
||||||
|
if (!query || query.length < Number(minSearchLength || 0)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (searchMode === "startsWith") {
|
||||||
|
return searchableText(option).startsWith(query.toLowerCase())
|
||||||
|
}
|
||||||
|
if (searchMode === "exact") {
|
||||||
|
return searchableText(option) === query.toLowerCase()
|
||||||
|
}
|
||||||
|
return searchableText(option).includes(query.toLowerCase())
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchingOptions(list) {
|
||||||
|
return list.filter((option) => matches(option))
|
||||||
|
}
|
||||||
|
|
||||||
|
function visibleOptions(list) {
|
||||||
|
if (searchResultLimit > 0) {
|
||||||
|
return matchingOptions(list).slice(0, Number(searchResultLimit))
|
||||||
|
}
|
||||||
|
return matchingOptions(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
function flatVisibleOptions() {
|
||||||
|
return visibleOptions(allOptions())
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSelected(option) {
|
||||||
|
return (
|
||||||
|
multiple
|
||||||
|
? selectedValues.includes(option.value)
|
||||||
|
: selectedValue === option.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectedOptions() {
|
||||||
|
return allOptions().filter((option) => isSelected(option))
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectedCount() {
|
||||||
|
return multiple ? selectedValues.length : selectedValue ? 1 : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function counterText() {
|
||||||
|
return (
|
||||||
|
maxSelections
|
||||||
|
? selectedCount() + " / " + maxSelections + " selected"
|
||||||
|
: selectedCount() + " selected"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectedText() {
|
||||||
|
return (
|
||||||
|
multiple
|
||||||
|
? selectedValues.join(", ")
|
||||||
|
: selectedOptions().length
|
||||||
|
? selectedOptions()[0].label
|
||||||
|
: ""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function triggerText() {
|
||||||
|
return selectedCount() ? selectedText() : placeholder
|
||||||
|
}
|
||||||
|
|
||||||
|
function canSelect(option) {
|
||||||
|
if (option.disabled) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!multiple || isSelected(option)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (maxSelections <= 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return selectedCount() < maxSelections
|
||||||
|
}
|
||||||
|
|
||||||
|
function chooseSingle(option) {
|
||||||
|
if (!canSelect(option)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
selectedValue = option.value
|
||||||
|
query = ""
|
||||||
|
if (closeOnSelect) {
|
||||||
|
open = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function chooseMultiple(option) {
|
||||||
|
if (!canSelect(option)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (isSelected(option)) {
|
||||||
|
selectedValues = selectedValues.filter((item) => item !== option.value)
|
||||||
|
} else {
|
||||||
|
selectedValues = selectedValues.concat([option.value])
|
||||||
|
}
|
||||||
|
query = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
function chooseOption(option) {
|
||||||
|
if (multiple) {
|
||||||
|
chooseMultiple(option)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
chooseSingle(option)
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearSelection(event) {
|
||||||
|
event.stopPropagation()
|
||||||
|
selectedValue = ""
|
||||||
|
selectedValues = []
|
||||||
|
query = ""
|
||||||
|
open = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
if (disabled) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
open = !open;
|
||||||
|
activeIndex = open && flatVisibleOptions().length ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveActive(direction) {
|
||||||
|
if (!flatVisibleOptions().length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
activeIndex = (activeIndex + direction + flatVisibleOptions().length) % flatVisibleOptions().length
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleKeydown(event) {
|
||||||
|
if (disabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (event.key === "ArrowDown") {
|
||||||
|
event.preventDefault()
|
||||||
|
if (!open) {
|
||||||
|
open = true
|
||||||
|
}
|
||||||
|
moveActive(1)
|
||||||
|
} else if (event.key === "ArrowUp") {
|
||||||
|
event.preventDefault()
|
||||||
|
if (!open) {
|
||||||
|
open = true
|
||||||
|
}
|
||||||
|
moveActive(-1)
|
||||||
|
} else if (event.key === "Enter" || event.key === " ") {
|
||||||
|
event.preventDefault()
|
||||||
|
if (!open) {
|
||||||
|
open = true
|
||||||
|
} else if (activeIndex >= 0) {
|
||||||
|
chooseOption(flatVisibleOptions()[activeIndex])
|
||||||
|
}
|
||||||
|
} else if (event.key === "Escape") {
|
||||||
|
open = false
|
||||||
|
} else if (event.key === "Home" && open) {
|
||||||
|
event.preventDefault()
|
||||||
|
activeIndex = 0
|
||||||
|
} else if (event.key === "End" && open) {
|
||||||
|
event.preventDefault()
|
||||||
|
activeIndex = flatVisibleOptions().length - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function optionIndex(option) {
|
||||||
|
return flatVisibleOptions().findIndex((item) => item.value === option.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view {
|
||||||
|
<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}"
|
||||||
|
data-placement="{placement}"
|
||||||
|
data-search-mode="{searchMode}"
|
||||||
|
data-remote="{remote ? 'true' : 'false'}"
|
||||||
|
data-remote-url="{remoteUrl}"
|
||||||
|
data-remote-query-param="{remoteQueryParam}"
|
||||||
|
data-remote-debounce="{remoteDebounce}"
|
||||||
|
data-remote-auto-load="{remoteAutoLoad ? 'true' : 'false'}"
|
||||||
|
data-infinite="{infinite ? 'true' : 'false'}"
|
||||||
|
data-page="{page}"
|
||||||
|
data-wrn-select
|
||||||
|
@focusout="if (!event.currentTarget.contains(event.relatedTarget)) { open = false }"
|
||||||
|
>
|
||||||
|
<div class="wire-next__row">
|
||||||
|
<label id="{name}-label" for="{name}-trigger">{label}</label>
|
||||||
|
<small data-show="showCounter" data-text="counterText()">{counterText()}</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wire-next__select-control">
|
||||||
|
<button
|
||||||
|
{...attrs}
|
||||||
|
id="{name}-trigger"
|
||||||
|
type="button"
|
||||||
|
class="wire-next__select-trigger"
|
||||||
|
role="combobox"
|
||||||
|
aria-haspopup="listbox"
|
||||||
|
aria-expanded="{open}"
|
||||||
|
aria-controls="{name}-listbox"
|
||||||
|
aria-labelledby="{name}-label"
|
||||||
|
aria-invalid="{invalid}"
|
||||||
|
disabled="{disabled}"
|
||||||
|
@click="toggle()"
|
||||||
|
@keydown="handleKeydown(event)"
|
||||||
|
>
|
||||||
|
<span class="wire-next__select-value">
|
||||||
|
<span data-show="!multiple" data-text="triggerText()">{triggerText()}</span>
|
||||||
|
<span
|
||||||
|
data-show="multiple && selectedTemplate === 'count' && selectedCount() > 0"
|
||||||
|
data-text="selectedCount() + ' selected'"
|
||||||
|
>{selectedCount()} selected</span>
|
||||||
|
<span
|
||||||
|
data-show="multiple && selectedTemplate === 'text' && selectedCount() > 0"
|
||||||
|
data-text="selectedText()"
|
||||||
|
>{selectedText()}</span>
|
||||||
|
<span
|
||||||
|
class="wire-next__select-tags"
|
||||||
|
aria-label="{selectedOptionsLabel}"
|
||||||
|
data-show="multiple && selectedTemplate !== 'count' && selectedTemplate !== 'text' && selectedCount() > 0"
|
||||||
|
>
|
||||||
|
{#each allOptions() as option}
|
||||||
|
<span data-show="isSelected(option)">
|
||||||
|
{#if optionTemplate === "icon" && option.icon}<i class="{option.icon}" aria-hidden="true"></i>{/if}
|
||||||
|
{#if optionTemplate === "avatar" && option.avatar}<img src="{option.avatar}" alt="" />{/if}
|
||||||
|
{#if optionTemplate === "color" && option.color}<i class="wire-next__color-dot" style="--option-color: {option.color}"></i>{/if}
|
||||||
|
{option.label}
|
||||||
|
</span>
|
||||||
|
{/each}
|
||||||
|
</span>
|
||||||
|
<span data-show="multiple && selectedCount() === 0">
|
||||||
|
{#if placeholderIcon}<i class="{placeholderIcon}" aria-hidden="true"></i>{/if}
|
||||||
|
<span class="wire-next__placeholder">{placeholder}</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="wire-next__select-chevron icon-[lucide--chevrons-up-down]"
|
||||||
|
aria-hidden="true"
|
||||||
|
></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="wire-next__clear-select"
|
||||||
|
data-show="clearable && allowEmpty && selectedCount() > 0 && !disabled"
|
||||||
|
aria-label="{clearLabel}"
|
||||||
|
title="{clearLabel}"
|
||||||
|
@click="clearSelection(event)"
|
||||||
|
>
|
||||||
|
<span class="icon-[lucide--x]" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="wire-next__select-dropdown {fixed ? 'wire-next__select-dropdown--fixed' : ''}"
|
||||||
|
data-show="open"
|
||||||
|
style="{open ? '' : 'display: none'}"
|
||||||
|
>
|
||||||
|
{#if searchable}
|
||||||
|
<label class="wire-next__select-search">
|
||||||
|
<span class="wire-visually-hidden">{searchPlaceholder}</span>
|
||||||
|
<span class="wire-next__search-icon" aria-hidden="true">⌕</span>
|
||||||
|
<input
|
||||||
|
type="search"
|
||||||
|
value="{query}"
|
||||||
|
placeholder="{searchPlaceholder}"
|
||||||
|
autocomplete="off"
|
||||||
|
@input="query = event.target.value; activeIndex = flatVisibleOptions().length ? 0 : -1"
|
||||||
|
@keydown="handleKeydown(event)"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="wire-next__select-message"
|
||||||
|
data-show="remote && query.length !== 0 && query.length < minSearchLength"
|
||||||
|
>Enter at least {minSearchLength} characters.</div>
|
||||||
|
<div class="wire-next__select-message" data-show="loading" role="status">
|
||||||
|
<i class="wire-spinner wire-spinner--inline" aria-hidden="true"></i>
|
||||||
|
{loadingLabel}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
id="{name}-listbox"
|
||||||
|
class="wire-next__select-list"
|
||||||
|
data-show="(!remote || (query.length === 0 && remoteAutoLoad) || query.length >= minSearchLength) && !loading"
|
||||||
|
role="listbox"
|
||||||
|
aria-multiselectable="{multiple}"
|
||||||
|
>
|
||||||
|
{#each groups as group}
|
||||||
|
{#if visibleOptions(group.options || []).length}
|
||||||
|
<div class="wire-next__option-group" role="group" aria-label="{group.label}">
|
||||||
|
<div class="wire-next__group-label">{group.label}</div>
|
||||||
|
{#each group.options || [] as option}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="wire-next__select-option {isSelected(option) ? 'wire-next__select-option--selected' : ''} {optionIndex(option) === activeIndex ? 'wire-next__select-option--active' : ''}"
|
||||||
|
data-option-value="{option.value}"
|
||||||
|
data-show="matches(option)"
|
||||||
|
role="option"
|
||||||
|
aria-selected="{isSelected(option)}"
|
||||||
|
disabled="{!canSelect(option)}"
|
||||||
|
@mouseenter="activeIndex = optionIndex(option)"
|
||||||
|
@click="chooseOption(option)"
|
||||||
|
>
|
||||||
|
{#if optionTemplate === "icon" && option.icon}<i class="{option.icon}" aria-hidden="true"></i>{/if}
|
||||||
|
{#if optionTemplate === "avatar" && option.avatar}<img src="{option.avatar}" alt="" />{/if}
|
||||||
|
{#if optionTemplate === "color" && option.color}<i class="wire-next__color-dot" style="--option-color: {option.color}"></i>{/if}
|
||||||
|
<span><strong>{option.label}</strong>{#if option.description}<small>{option.description}</small>{/if}</span>
|
||||||
|
<i
|
||||||
|
class="wire-next__check icon-[lucide--check]"
|
||||||
|
data-show="isSelected(option)"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
{#each options as option}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="wire-next__select-option {isSelected(option) ? 'wire-next__select-option--selected' : ''} {optionIndex(option) === activeIndex ? 'wire-next__select-option--active' : ''}"
|
||||||
|
data-option-value="{option.value}"
|
||||||
|
data-show="matches(option)"
|
||||||
|
role="option"
|
||||||
|
aria-selected="{isSelected(option)}"
|
||||||
|
disabled="{!canSelect(option)}"
|
||||||
|
@mouseenter="activeIndex = optionIndex(option)"
|
||||||
|
@click="chooseOption(option)"
|
||||||
|
>
|
||||||
|
{#if optionTemplate === "icon" && option.icon}<i class="{option.icon}" aria-hidden="true"></i>{/if}
|
||||||
|
{#if optionTemplate === "avatar" && option.avatar}<img src="{option.avatar}" alt="" />{/if}
|
||||||
|
{#if optionTemplate === "color" && option.color}<i class="wire-next__color-dot" style="--option-color: {option.color}"></i>{/if}
|
||||||
|
<span><strong>{option.label}</strong>{#if option.description}<small>{option.description}</small>{/if}</span>
|
||||||
|
<i
|
||||||
|
class="wire-next__check icon-[lucide--check]"
|
||||||
|
data-show="isSelected(option)"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
{#if !loading && !flatVisibleOptions().length}
|
||||||
|
<div class="wire-next__select-message">{emptyLabel}</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if tags && query && !allOptions().some((option) => option.label.toLowerCase() === query.toLowerCase())}
|
||||||
|
<button type="button" class="wire-next__create-option">{createLabel} “{query}”</button>
|
||||||
|
{/if}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="wire-next__load-more"
|
||||||
|
data-wrn-select-load-more
|
||||||
|
data-show="infinite && hasMore"
|
||||||
|
>{loadMoreLabel}</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="{name}"
|
||||||
|
value="{multiple ? selectedValues.join(',') : selectedValue}"
|
||||||
|
required="{required}"
|
||||||
|
aria-describedby="{validationMessage ? `${name}-validation` : helpText ? `${name}-help` : ''}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{#if helpText && !validationMessage}<small id="{name}-help">{helpText}</small>{/if}
|
||||||
|
<small
|
||||||
|
id="{name}-validation"
|
||||||
|
class="wire-next__validation"
|
||||||
|
data-error="{name}"
|
||||||
|
>{validationMessage}</small>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component AvatarGroup {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Avatar Group"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--avatar-group wire-next--variant-{variant} {class}">
|
||||||
|
{#if title}<strong>{title}</strong>{/if}
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Blockquote {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Blockquote"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--blockquote wire-next--variant-{variant} {class}">
|
||||||
|
{#if title}<strong>{title}</strong>{/if}
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
component Breadcrumb {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Breadcrumb"
|
||||||
|
items = []
|
||||||
|
active = ""
|
||||||
|
orientation = "horizontal"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<nav class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--breadcrumb wire-next--{orientation} {class}" aria-label="{label}">
|
||||||
|
{#each items as item}<a href="{item.href}" aria-current="{item.value === active ? 'page' : ''}">{item.label}</a>{/each}
|
||||||
|
<slot />
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component ButtonGroup {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Button Group"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--button-group wire-next--variant-{variant} {class}">
|
||||||
|
{#if title}<strong>{title}</strong>{/if}
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Carousel {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Carousel"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--carousel wire-next--variant-{variant} {class}">
|
||||||
|
{#if title}<strong>{title}</strong>{/if}
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Chart {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Chart"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--chart 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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component ChatBubble {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Chat Bubble"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--chat-bubble wire-next--variant-{variant} {class}">
|
||||||
|
{#if title}<strong>{title}</strong>{/if}
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Clipboard {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Clipboard"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--clipboard 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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
component Collapse {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
items = []
|
||||||
|
multiple = false
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--collapse {class}">
|
||||||
|
{#each items as item}<details open="{item.open}"><summary>{item.label}</summary><div>{item.content}</div></details>{/each}
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
component ColorPicker {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Color Picker"
|
||||||
|
name = ""
|
||||||
|
value = ""
|
||||||
|
placeholder = ""
|
||||||
|
type = "color"
|
||||||
|
min = ""
|
||||||
|
max = ""
|
||||||
|
step = ""
|
||||||
|
disabled = false
|
||||||
|
required = false
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<label class="wire-next wire-next--field wire-next--color-picker {class}"><span>{label}</span><input {...attrs} type="{type}" name="{name}" value="{value}" placeholder="{placeholder}" min="{min}" max="{max}" step="{step}" disabled="{disabled}" required="{required}" /></label>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
component Columns {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
columns = 2
|
||||||
|
gap = "md"
|
||||||
|
maxWidth = "xl"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--columns wire-next--gap-{gap} wire-next--columns-{columns} wire-next--max-{maxWidth} {class}"><slot /></div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,386 @@
|
|||||||
|
component ComboBox {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "ComboBox"
|
||||||
|
name = ""
|
||||||
|
value = ""
|
||||||
|
options = []
|
||||||
|
groups = []
|
||||||
|
placeholder = "Search or select an option"
|
||||||
|
searchPlaceholder = "Start typing…"
|
||||||
|
clearable = true
|
||||||
|
allowCustomValue = false
|
||||||
|
disabled = false
|
||||||
|
required = false
|
||||||
|
invalid = false
|
||||||
|
validationMessage = ""
|
||||||
|
helpText = ""
|
||||||
|
loading = false
|
||||||
|
loadingLabel = "Loading suggestions…"
|
||||||
|
emptyLabel = "No matching options"
|
||||||
|
clearLabel = "Clear value"
|
||||||
|
toggleLabel = "Toggle suggestions"
|
||||||
|
searchMode = "contains"
|
||||||
|
searchFields = "label,description"
|
||||||
|
minSearchLength = 0
|
||||||
|
searchResultLimit = 0
|
||||||
|
optionTemplate = "default"
|
||||||
|
defaultOpen = false
|
||||||
|
closeOnSelect = true
|
||||||
|
fixed = false
|
||||||
|
placement = "bottom"
|
||||||
|
autocomplete = "off"
|
||||||
|
remote = false
|
||||||
|
remoteUrl = ""
|
||||||
|
remoteQueryParam = "q"
|
||||||
|
remoteDebounce = 250
|
||||||
|
remoteAutoLoad = true
|
||||||
|
infinite = false
|
||||||
|
hasMore = false
|
||||||
|
page = 1
|
||||||
|
loadMoreLabel = "Load more"
|
||||||
|
class = ""
|
||||||
|
@event search = function
|
||||||
|
@event select = function
|
||||||
|
@event change = function
|
||||||
|
@event clear = function
|
||||||
|
@event open = function
|
||||||
|
@event close = function
|
||||||
|
@event load = function
|
||||||
|
@event error = function
|
||||||
|
}
|
||||||
|
|
||||||
|
state open = defaultOpen
|
||||||
|
state query = ""
|
||||||
|
state selectedValue = value
|
||||||
|
state activeIndex = -1
|
||||||
|
|
||||||
|
functions {
|
||||||
|
function allOptions() {
|
||||||
|
return [...groups.flatMap((group) => group.options || []), ...options]
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchableText(option) {
|
||||||
|
return ((option.label || "") + " " + (option.description || "")).toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
function matches(option) {
|
||||||
|
if (!query || query.length < minSearchLength) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (searchMode === "startsWith") {
|
||||||
|
return searchableText(option).startsWith(query.toLowerCase())
|
||||||
|
}
|
||||||
|
if (searchMode === "exact") {
|
||||||
|
return searchableText(option) === query.toLowerCase()
|
||||||
|
}
|
||||||
|
return searchableText(option).includes(query.toLowerCase())
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchingOptions(list) {
|
||||||
|
return list.filter((option) => matches(option))
|
||||||
|
}
|
||||||
|
|
||||||
|
function visibleOptions(list) {
|
||||||
|
if (searchResultLimit > 0) {
|
||||||
|
return matchingOptions(list).slice(0, searchResultLimit)
|
||||||
|
}
|
||||||
|
return matchingOptions(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
function flatVisibleOptions() {
|
||||||
|
return visibleOptions(allOptions())
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSelected(option) {
|
||||||
|
return selectedValue === option.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectedOptions() {
|
||||||
|
return allOptions().filter((option) => isSelected(option))
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectedText() {
|
||||||
|
return selectedOptions().length ? selectedOptions()[0].label : selectedValue
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputText() {
|
||||||
|
return query || selectedText()
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldShowDropdown() {
|
||||||
|
if (!open) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (loading) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (remote && query.length !== 0 && query.length < minSearchLength) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (flatVisibleOptions().length) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return infinite && hasMore
|
||||||
|
}
|
||||||
|
|
||||||
|
function canSelect(option) {
|
||||||
|
return !option.disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
function chooseOption(option) {
|
||||||
|
if (!canSelect(option)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
selectedValue = option.value
|
||||||
|
query = option.label
|
||||||
|
activeIndex = optionIndex(option)
|
||||||
|
if (closeOnSelect) {
|
||||||
|
open = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateQuery(event) {
|
||||||
|
query = event.target.value
|
||||||
|
selectedValue = allowCustomValue ? event.target.value : ""
|
||||||
|
open = true
|
||||||
|
activeIndex = flatVisibleOptions().length ? 0 : -1
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearValue(event) {
|
||||||
|
if (event) {
|
||||||
|
event.stopPropagation()
|
||||||
|
}
|
||||||
|
query = ""
|
||||||
|
selectedValue = ""
|
||||||
|
activeIndex = -1
|
||||||
|
open = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function openDropdown() {
|
||||||
|
if (!disabled) {
|
||||||
|
open = true
|
||||||
|
activeIndex = flatVisibleOptions().length ? 0 : -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeDropdown() {
|
||||||
|
open = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
if (open) {
|
||||||
|
closeDropdown()
|
||||||
|
} else {
|
||||||
|
openDropdown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setValue(nextValue) {
|
||||||
|
selectedValue = nextValue
|
||||||
|
query = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveActive(direction) {
|
||||||
|
if (!flatVisibleOptions().length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
activeIndex = (activeIndex + direction + flatVisibleOptions().length) % flatVisibleOptions().length
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleKeydown(event) {
|
||||||
|
if (disabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (event.key === "ArrowDown") {
|
||||||
|
event.preventDefault()
|
||||||
|
openDropdown()
|
||||||
|
moveActive(1)
|
||||||
|
} else if (event.key === "ArrowUp") {
|
||||||
|
event.preventDefault()
|
||||||
|
openDropdown()
|
||||||
|
moveActive(-1)
|
||||||
|
} else if (event.key === "Enter" && open && activeIndex >= 0) {
|
||||||
|
event.preventDefault()
|
||||||
|
chooseOption(flatVisibleOptions()[activeIndex])
|
||||||
|
} else if (event.key === "Escape") {
|
||||||
|
closeDropdown()
|
||||||
|
} else if (event.key === "Home" && open) {
|
||||||
|
event.preventDefault()
|
||||||
|
activeIndex = 0
|
||||||
|
} else if (event.key === "End" && open) {
|
||||||
|
event.preventDefault()
|
||||||
|
activeIndex = flatVisibleOptions().length - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function optionIndex(option) {
|
||||||
|
return flatVisibleOptions().findIndex((item) => item.value === option.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view {
|
||||||
|
<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}"
|
||||||
|
data-placement="{placement}"
|
||||||
|
data-search-mode="{searchMode}"
|
||||||
|
data-remote="{remote ? 'true' : 'false'}"
|
||||||
|
data-remote-url="{remoteUrl}"
|
||||||
|
data-remote-query-param="{remoteQueryParam}"
|
||||||
|
data-remote-debounce="{remoteDebounce}"
|
||||||
|
data-remote-auto-load="{remoteAutoLoad ? 'true' : 'false'}"
|
||||||
|
data-infinite="{infinite ? 'true' : 'false'}"
|
||||||
|
data-page="{page}"
|
||||||
|
data-wrn-select
|
||||||
|
data-wrn-combobox
|
||||||
|
@focusout="if (!event.currentTarget.contains(event.relatedTarget)) { closeDropdown() }"
|
||||||
|
>
|
||||||
|
<label id="{name}-label" for="{name}-input">{label}</label>
|
||||||
|
|
||||||
|
<div class="wire-next__select-control wire-next__combobox-control">
|
||||||
|
<span class="wire-next__search-icon icon-[lucide--search]" aria-hidden="true"></span>
|
||||||
|
<input
|
||||||
|
{...attrs}
|
||||||
|
id="{name}-input"
|
||||||
|
class="wire-next__select-trigger wire-next__combobox-input"
|
||||||
|
type="text"
|
||||||
|
role="combobox"
|
||||||
|
name="{allowCustomValue ? name : ''}"
|
||||||
|
value="{inputText()}"
|
||||||
|
placeholder="{placeholder}"
|
||||||
|
autocomplete="{autocomplete}"
|
||||||
|
aria-autocomplete="list"
|
||||||
|
aria-haspopup="listbox"
|
||||||
|
aria-expanded="{open}"
|
||||||
|
aria-controls="{name}-listbox"
|
||||||
|
aria-labelledby="{name}-label"
|
||||||
|
aria-invalid="{invalid}"
|
||||||
|
disabled="{disabled}"
|
||||||
|
required="{required && allowCustomValue}"
|
||||||
|
@focus="openDropdown()"
|
||||||
|
@click="openDropdown()"
|
||||||
|
@input="updateQuery(event)"
|
||||||
|
@keydown="handleKeydown(event)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="wire-next__clear-select"
|
||||||
|
data-show="clearable && inputText() && !disabled"
|
||||||
|
aria-label="{clearLabel}"
|
||||||
|
title="{clearLabel}"
|
||||||
|
@click="clearValue(event)"
|
||||||
|
>
|
||||||
|
<span class="icon-[lucide--x]" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="wire-next__combobox-toggle"
|
||||||
|
aria-label="{toggleLabel}"
|
||||||
|
tabindex="-1"
|
||||||
|
disabled="{disabled}"
|
||||||
|
@click="toggle()"
|
||||||
|
>
|
||||||
|
<span class="wire-next__select-chevron icon-[lucide--chevrons-up-down]" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="wire-next__select-dropdown {fixed ? 'wire-next__select-dropdown--fixed' : ''}"
|
||||||
|
data-show="shouldShowDropdown()"
|
||||||
|
style="{shouldShowDropdown() ? '' : 'display: none'}"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="wire-next__select-message"
|
||||||
|
data-show="remote && query.length !== 0 && query.length < minSearchLength"
|
||||||
|
>Enter at least {minSearchLength} characters.</div>
|
||||||
|
<div class="wire-next__select-message" data-show="loading" role="status">
|
||||||
|
<i class="wire-spinner wire-spinner--inline" aria-hidden="true"></i>
|
||||||
|
{loadingLabel}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id="{name}-listbox"
|
||||||
|
class="wire-next__select-list"
|
||||||
|
data-show="(!remote || (query.length === 0 && remoteAutoLoad) || query.length >= minSearchLength) && !loading"
|
||||||
|
role="listbox"
|
||||||
|
>
|
||||||
|
{#each groups as group}
|
||||||
|
{#if visibleOptions(group.options || []).length}
|
||||||
|
<div class="wire-next__option-group" role="group" aria-label="{group.label}">
|
||||||
|
<div class="wire-next__group-label">{group.label}</div>
|
||||||
|
{#each group.options || [] as option}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="wire-next__select-option {isSelected(option) ? 'wire-next__select-option--selected' : ''} {optionIndex(option) === activeIndex ? 'wire-next__select-option--active' : ''}"
|
||||||
|
data-option-value="{option.value}"
|
||||||
|
data-show="matches(option)"
|
||||||
|
role="option"
|
||||||
|
aria-selected="{isSelected(option)}"
|
||||||
|
disabled="{!canSelect(option)}"
|
||||||
|
@mouseenter="activeIndex = optionIndex(option)"
|
||||||
|
@mousedown="event.preventDefault()"
|
||||||
|
@click="chooseOption(option)"
|
||||||
|
>
|
||||||
|
{#if optionTemplate === "icon" && option.icon}<i class="{option.icon}" aria-hidden="true"></i>{/if}
|
||||||
|
{#if optionTemplate === "avatar" && option.avatar}<img src="{option.avatar}" alt="" />{/if}
|
||||||
|
{#if optionTemplate === "color" && option.color}<i class="wire-next__color-dot" style="--option-color: {option.color}"></i>{/if}
|
||||||
|
<span><strong>{option.label}</strong>{#if option.description}<small>{option.description}</small>{/if}</span>
|
||||||
|
<i class="wire-next__check icon-[lucide--check]" data-show="isSelected(option)" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
{#each options as option}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="wire-next__select-option {isSelected(option) ? 'wire-next__select-option--selected' : ''} {optionIndex(option) === activeIndex ? 'wire-next__select-option--active' : ''}"
|
||||||
|
data-option-value="{option.value}"
|
||||||
|
data-show="matches(option)"
|
||||||
|
role="option"
|
||||||
|
aria-selected="{isSelected(option)}"
|
||||||
|
disabled="{!canSelect(option)}"
|
||||||
|
@mouseenter="activeIndex = optionIndex(option)"
|
||||||
|
@mousedown="event.preventDefault()"
|
||||||
|
@click="chooseOption(option)"
|
||||||
|
>
|
||||||
|
{#if optionTemplate === "icon" && option.icon}<i class="{option.icon}" aria-hidden="true"></i>{/if}
|
||||||
|
{#if optionTemplate === "avatar" && option.avatar}<img src="{option.avatar}" alt="" />{/if}
|
||||||
|
{#if optionTemplate === "color" && option.color}<i class="wire-next__color-dot" style="--option-color: {option.color}"></i>{/if}
|
||||||
|
<span><strong>{option.label}</strong>{#if option.description}<small>{option.description}</small>{/if}</span>
|
||||||
|
<i class="wire-next__check icon-[lucide--check]" data-show="isSelected(option)" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="wire-next__load-more"
|
||||||
|
data-wrn-select-load-more
|
||||||
|
data-show="infinite && hasMore"
|
||||||
|
>{loadMoreLabel}</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if !allowCustomValue}
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="{name}"
|
||||||
|
value="{selectedValue}"
|
||||||
|
required="{required}"
|
||||||
|
data-error="{name}"
|
||||||
|
aria-describedby="{validationMessage ? `${name}-validation` : helpText ? `${name}-help` : ''}"
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if helpText && !validationMessage}<small id="{name}-help">{helpText}</small>{/if}
|
||||||
|
<small
|
||||||
|
id="{name}-validation"
|
||||||
|
class="wire-next__validation"
|
||||||
|
data-error="{name}"
|
||||||
|
>{validationMessage}</small>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Confetti {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Confetti"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--confetti 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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component ContextMenu {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Context Menu"
|
||||||
|
description = ""
|
||||||
|
open = false
|
||||||
|
placement = "bottom"
|
||||||
|
closeLabel = "Close"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<div data-show="{open}" class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--context-menu wire-next--placement-{placement} {class}" role="region" aria-modal="false" aria-label="{title}">
|
||||||
|
<header><strong>{title}</strong><button type="button" aria-label="{closeLabel}">×</button></header>
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
component CopyMarkup {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Copy Markup"
|
||||||
|
name = ""
|
||||||
|
value = ""
|
||||||
|
placeholder = ""
|
||||||
|
type = "text"
|
||||||
|
min = ""
|
||||||
|
max = ""
|
||||||
|
step = ""
|
||||||
|
disabled = false
|
||||||
|
required = false
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
component CustomScrollbar {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
columns = 2
|
||||||
|
gap = "md"
|
||||||
|
maxWidth = "xl"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--custom-scrollbar wire-next--gap-{gap} wire-next--columns-{columns} wire-next--max-{maxWidth} {class}"><slot /></div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component DataMap {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Data Map"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--data-map wire-next--variant-{variant} {class}">
|
||||||
|
{#if title}<strong>{title}</strong>{/if}
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
component DataTable {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
caption = "Data Table"
|
||||||
|
columns = []
|
||||||
|
rows = []
|
||||||
|
striped = true
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--table {class}"><table><caption>{caption}</caption><thead><tr>{#each columns as column}<th>{column.label}</th>{/each}</tr></thead><tbody>{#each rows as row}<tr>{#each columns as column}<td>{row[column.key]}</td>{/each}</tr>{/each}</tbody></table><slot /></div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
component DatePicker {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Date Picker"
|
||||||
|
name = ""
|
||||||
|
value = ""
|
||||||
|
placeholder = ""
|
||||||
|
type = "date"
|
||||||
|
min = ""
|
||||||
|
max = ""
|
||||||
|
step = ""
|
||||||
|
disabled = false
|
||||||
|
required = false
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--date-picker {class}"><span>{label}</span><input {...attrs} type="{type}" name="{name}" value="{value}" placeholder="{placeholder}" min="{min}" max="{max}" step="{step}" disabled="{disabled}" required="{required}" /></label>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component DeviceFrame {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Device Frame"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--device-frame wire-next--variant-{variant} {class}">
|
||||||
|
{#if title}<strong>{title}</strong>{/if}
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component DragAndDrop {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Drag And Drop"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--drag-and-drop 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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Drawer {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Drawer"
|
||||||
|
description = ""
|
||||||
|
open = false
|
||||||
|
placement = "bottom"
|
||||||
|
closeLabel = "Close"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<div data-show="{open}" class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--drawer wire-next--placement-{placement} {class}" role="dialog" aria-modal="true" aria-label="{title}">
|
||||||
|
<header><strong>{title}</strong><button type="button" aria-label="{closeLabel}">×</button></header>
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Dropdown {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Dropdown"
|
||||||
|
description = ""
|
||||||
|
open = false
|
||||||
|
placement = "bottom"
|
||||||
|
closeLabel = "Close"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<div data-show="{open}" class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--dropdown wire-next--placement-{placement} {class}" role="region" aria-modal="false" aria-label="{title}">
|
||||||
|
<header><strong>{title}</strong><button type="button" aria-label="{closeLabel}">×</button></header>
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
component FileInput {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "File Input"
|
||||||
|
name = ""
|
||||||
|
value = ""
|
||||||
|
placeholder = ""
|
||||||
|
type = "file"
|
||||||
|
min = ""
|
||||||
|
max = ""
|
||||||
|
step = ""
|
||||||
|
disabled = false
|
||||||
|
required = false
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--file-input {class}"><span>{label}</span><input {...attrs} type="{type}" name="{name}" value="{value}" placeholder="{placeholder}" min="{min}" max="{max}" step="{step}" disabled="{disabled}" required="{required}" /></label>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component FileUpload {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "File Upload"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
component FileUploadProgress {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Progress"
|
||||||
|
value = 50
|
||||||
|
max = 100
|
||||||
|
showValue = true
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--file-upload-progress {class}">
|
||||||
|
<div class="wire-next__row"><span>{label}</span>{#if showValue}<strong>{value}%</strong>{/if}</div>
|
||||||
|
<progress value="{value}" max="{max}"></progress>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Image {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
src = ""
|
||||||
|
alt = ""
|
||||||
|
width = ""
|
||||||
|
height = ""
|
||||||
|
loading = "lazy"
|
||||||
|
rounded = false
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<figure class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--image {rounded ? 'wire-next--rounded' : ''} {class}">
|
||||||
|
<img src="{src}" alt="{alt}" width="{width}" height="{height}" loading="{loading}" />
|
||||||
|
<slot />
|
||||||
|
</figure>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
component InputGroup {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Input Group"
|
||||||
|
name = ""
|
||||||
|
value = ""
|
||||||
|
placeholder = ""
|
||||||
|
type = "text"
|
||||||
|
min = ""
|
||||||
|
max = ""
|
||||||
|
step = ""
|
||||||
|
disabled = false
|
||||||
|
required = false
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--input-group {class}"><span>{label}</span><input {...attrs} type="{type}" name="{name}" value="{value}" placeholder="{placeholder}" min="{min}" max="{max}" step="{step}" disabled="{disabled}" required="{required}" /></label>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
component InputNumber {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Input Number"
|
||||||
|
name = ""
|
||||||
|
value = ""
|
||||||
|
placeholder = ""
|
||||||
|
type = "number"
|
||||||
|
min = ""
|
||||||
|
max = ""
|
||||||
|
step = ""
|
||||||
|
disabled = false
|
||||||
|
required = false
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--input-number {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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
component Kbd {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "⌘ K"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view { <kbd class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--kbd {class}"><slot>{label}</slot></kbd> }
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
component LayoutSplitter {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
columns = 2
|
||||||
|
gap = "md"
|
||||||
|
maxWidth = "xl"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<div class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--layout-splitter wire-next--gap-{gap} wire-next--columns-{columns} wire-next--max-{maxWidth} {class}"><slot /></div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component LegendIndicator {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Legend Indicator"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--legend-indicator 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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
component Link {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Link"
|
||||||
|
href = "#"
|
||||||
|
target = ""
|
||||||
|
rel = ""
|
||||||
|
external = false
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<a {...attrs} href="{href}" target="{target}" rel="{rel}" class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--link {class}"><slot>{label}</slot>{#if external}<span aria-hidden="true">↗</span>{/if}</a>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component List {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "List"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--list wire-next--variant-{variant} {class}">
|
||||||
|
{#if title}<strong>{title}</strong>{/if}
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component ListGroup {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "List Group"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--list-group wire-next--variant-{variant} {class}">
|
||||||
|
{#if title}<strong>{title}</strong>{/if}
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Map {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Map"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--map wire-next--variant-{variant} {class}">
|
||||||
|
{#if title}<strong>{title}</strong>{/if}
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Marquee {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Marquee"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--marquee wire-next--variant-{variant} {class}">
|
||||||
|
{#if title}<strong>{title}</strong>{/if}
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
component MegaMenu {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Mega Menu"
|
||||||
|
items = []
|
||||||
|
active = ""
|
||||||
|
orientation = "horizontal"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<nav class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--mega-menu wire-next--{orientation} {class}" aria-label="{label}">
|
||||||
|
{#each items as item}<a href="{item.href}" aria-current="{item.value === active ? 'page' : ''}">{item.label}</a>{/each}
|
||||||
|
<slot />
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Modal {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Modal"
|
||||||
|
description = ""
|
||||||
|
open = false
|
||||||
|
placement = "bottom"
|
||||||
|
closeLabel = "Close"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<div data-show="{open}" class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--modal wire-next--placement-{placement} {class}" role="dialog" aria-modal="true" aria-label="{title}">
|
||||||
|
<header><strong>{title}</strong><button type="button" aria-label="{closeLabel}">×</button></header>
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
component Nav {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Nav"
|
||||||
|
items = []
|
||||||
|
active = ""
|
||||||
|
orientation = "horizontal"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<nav class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--nav wire-next--{orientation} {class}" aria-label="{label}">
|
||||||
|
{#each items as item}<a href="{item.href}" aria-current="{item.value === active ? 'page' : ''}">{item.label}</a>{/each}
|
||||||
|
<slot />
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
component Navbar {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Navbar"
|
||||||
|
items = []
|
||||||
|
active = ""
|
||||||
|
orientation = "horizontal"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<nav class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--navbar wire-next--{orientation} {class}" aria-label="{label}">
|
||||||
|
{#each items as item}<a href="{item.href}" aria-current="{item.value === active ? 'page' : ''}">{item.label}</a>{/each}
|
||||||
|
<slot />
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
component Pagination {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Pagination"
|
||||||
|
items = []
|
||||||
|
active = ""
|
||||||
|
orientation = "horizontal"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<nav class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--pagination wire-next--{orientation} {class}" aria-label="{label}">
|
||||||
|
{#each items as item}<a href="{item.href}" aria-current="{item.value === active ? 'page' : ''}">{item.label}</a>{/each}
|
||||||
|
<slot />
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
component PinInput {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Verification code"
|
||||||
|
name = "pin"
|
||||||
|
value = ""
|
||||||
|
length = 4
|
||||||
|
pattern = "[0-9]"
|
||||||
|
type = "text"
|
||||||
|
inputMode = "numeric"
|
||||||
|
placeholder = "○"
|
||||||
|
autocomplete = "one-time-code"
|
||||||
|
masked = false
|
||||||
|
disabled = false
|
||||||
|
readonly = false
|
||||||
|
required = false
|
||||||
|
autoFocus = false
|
||||||
|
autoSubmit = false
|
||||||
|
allowPaste = true
|
||||||
|
clearable = true
|
||||||
|
clearLabel = "Clear code"
|
||||||
|
separator = ""
|
||||||
|
groupSize = 0
|
||||||
|
helpText = ""
|
||||||
|
invalid = false
|
||||||
|
validationMessage = ""
|
||||||
|
class = ""
|
||||||
|
@event input = function
|
||||||
|
@event change = function
|
||||||
|
@event complete = function
|
||||||
|
@event paste = function
|
||||||
|
@event clear = function
|
||||||
|
@event error = function
|
||||||
|
}
|
||||||
|
|
||||||
|
functions {
|
||||||
|
function inputIndexes() {
|
||||||
|
return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].slice(
|
||||||
|
0,
|
||||||
|
Math.max(1, Math.min(12, Number(length)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view {
|
||||||
|
<fieldset
|
||||||
|
{...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}"
|
||||||
|
data-wrn-pin-input
|
||||||
|
data-length="{length}"
|
||||||
|
data-pattern="{pattern}"
|
||||||
|
data-allow-paste="{allowPaste ? 'true' : 'false'}"
|
||||||
|
data-auto-submit="{autoSubmit ? 'true' : 'false'}"
|
||||||
|
data-value="{value}"
|
||||||
|
disabled="{disabled}"
|
||||||
|
aria-describedby="{validationMessage ? `${name}-validation` : helpText ? `${name}-help` : ''}"
|
||||||
|
>
|
||||||
|
<div class="wire-next__pin-heading">
|
||||||
|
<legend>{label}</legend>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="wire-next__pin-clear"
|
||||||
|
data-pin-clear
|
||||||
|
aria-label="{clearLabel}"
|
||||||
|
title="{clearLabel}"
|
||||||
|
style="{clearable && value ? '' : 'display: none'}"
|
||||||
|
>
|
||||||
|
<span class="icon-[lucide--rotate-ccw]" aria-hidden="true"></span>
|
||||||
|
<span>{clearLabel}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wire-next__pin-cells" role="group" aria-label="{label}">
|
||||||
|
{#each inputIndexes() as index}
|
||||||
|
<input
|
||||||
|
data-pin-cell
|
||||||
|
data-pin-index="{index}"
|
||||||
|
id="{name}-{index}"
|
||||||
|
type="{masked ? 'password' : type}"
|
||||||
|
inputmode="{inputMode}"
|
||||||
|
maxlength="1"
|
||||||
|
value="{value[index] || ''}"
|
||||||
|
placeholder="{placeholder}"
|
||||||
|
autocomplete="{index === 0 ? autocomplete : 'off'}"
|
||||||
|
aria-label="{label} digit {index + 1} of {length}"
|
||||||
|
aria-required="{required ? 'true' : 'false'}"
|
||||||
|
readonly="{readonly}"
|
||||||
|
disabled="{disabled}"
|
||||||
|
autofocus="{autoFocus && index === 0}"
|
||||||
|
/>
|
||||||
|
{#if separator && groupSize !== 0 && (index + 1) % groupSize === 0 && index + 1 !== length}
|
||||||
|
<span class="wire-next__pin-separator" aria-hidden="true">{separator}</span>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="{name}"
|
||||||
|
value="{value}"
|
||||||
|
required="{required}"
|
||||||
|
data-pin-value
|
||||||
|
/>
|
||||||
|
|
||||||
|
{#if helpText && !validationMessage}<small id="{name}-help">{helpText}</small>{/if}
|
||||||
|
<small
|
||||||
|
id="{name}-validation"
|
||||||
|
class="wire-next__validation"
|
||||||
|
data-error="{name}"
|
||||||
|
>{validationMessage}</small>
|
||||||
|
</fieldset>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Popover {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Popover"
|
||||||
|
description = ""
|
||||||
|
open = false
|
||||||
|
placement = "bottom"
|
||||||
|
closeLabel = "Close"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<div data-show="{open}" class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--popover wire-next--placement-{placement} {class}" role="region" aria-modal="false" aria-label="{title}">
|
||||||
|
<header><strong>{title}</strong><button type="button" aria-label="{closeLabel}">×</button></header>
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
component RangeSlider {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Range Slider"
|
||||||
|
name = ""
|
||||||
|
value = ""
|
||||||
|
placeholder = ""
|
||||||
|
type = "range"
|
||||||
|
min = ""
|
||||||
|
max = ""
|
||||||
|
step = ""
|
||||||
|
disabled = false
|
||||||
|
required = false
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--range-slider {class}"><span>{label}</span><input {...attrs} type="{type}" name="{name}" value="{value}" placeholder="{placeholder}" min="{min}" max="{max}" step="{step}" disabled="{disabled}" required="{required}" /></label>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Rating {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Rating"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--rating 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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
component Scrollspy {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Scrollspy"
|
||||||
|
items = []
|
||||||
|
active = ""
|
||||||
|
orientation = "horizontal"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<nav class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--scrollspy wire-next--{orientation} {class}" aria-label="{label}">
|
||||||
|
{#each items as item}<a href="{item.href}" aria-current="{item.value === active ? 'page' : ''}">{item.label}</a>{/each}
|
||||||
|
<slot />
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
component SearchBox {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Search Box"
|
||||||
|
name = ""
|
||||||
|
value = ""
|
||||||
|
placeholder = ""
|
||||||
|
type = "search"
|
||||||
|
min = ""
|
||||||
|
max = ""
|
||||||
|
step = ""
|
||||||
|
disabled = false
|
||||||
|
required = false
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--search-box {class}"><span>{label}</span><input {...attrs} type="{type}" name="{name}" value="{value}" placeholder="{placeholder}" min="{min}" max="{max}" step="{step}" disabled="{disabled}" required="{required}" /></label>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
component Sidebar {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Sidebar"
|
||||||
|
items = []
|
||||||
|
active = ""
|
||||||
|
orientation = "horizontal"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<nav class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--sidebar wire-next--{orientation} {class}" aria-label="{label}">
|
||||||
|
{#each items as item}<a href="{item.href}" aria-current="{item.value === active ? 'page' : ''}">{item.label}</a>{/each}
|
||||||
|
<slot />
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
component Stepper {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Stepper"
|
||||||
|
items = []
|
||||||
|
active = ""
|
||||||
|
orientation = "horizontal"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<nav class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--stepper wire-next--{orientation} {class}" aria-label="{label}">
|
||||||
|
{#each items as item}<a href="{item.href}" aria-current="{item.value === active ? 'page' : ''}">{item.label}</a>{/each}
|
||||||
|
<slot />
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
component StrongPassword {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Password"
|
||||||
|
name = "password"
|
||||||
|
value = ""
|
||||||
|
placeholder = "Create a strong password"
|
||||||
|
autocomplete = "new-password"
|
||||||
|
minLength = 8
|
||||||
|
specialCharactersSet = "!@#$%^&*()_+-=[]{}|;:,.<>?"
|
||||||
|
requireLowercase = true
|
||||||
|
requireUppercase = true
|
||||||
|
requireNumber = true
|
||||||
|
requireSpecialCharacter = true
|
||||||
|
showRequirements = true
|
||||||
|
presentation = "inline"
|
||||||
|
hintText = "Use a unique password you do not use elsewhere."
|
||||||
|
emptyLabel = "Enter a password"
|
||||||
|
weakLabel = "Weak"
|
||||||
|
fairLabel = "Fair"
|
||||||
|
goodLabel = "Good"
|
||||||
|
strongLabel = "Strong"
|
||||||
|
disabled = false
|
||||||
|
readonly = false
|
||||||
|
required = false
|
||||||
|
invalid = false
|
||||||
|
validationMessage = ""
|
||||||
|
class = ""
|
||||||
|
@event input = function
|
||||||
|
@event change = function
|
||||||
|
@event strength = function
|
||||||
|
}
|
||||||
|
|
||||||
|
state password = value
|
||||||
|
state detailsOpen = false
|
||||||
|
|
||||||
|
functions {
|
||||||
|
function hasMinimumLength() {
|
||||||
|
return password.length >= Number(minLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasLowercase() {
|
||||||
|
return password !== password.toUpperCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasUppercase() {
|
||||||
|
return password !== password.toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasNumber() {
|
||||||
|
return containsCharacterAt("0123456789", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasSpecialCharacter() {
|
||||||
|
return containsCharacterAt(specialCharactersSet, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
function containsCharacterAt(characters, index) {
|
||||||
|
if (index >= characters.length) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (password.includes(characters[index])) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return containsCharacterAt(characters, index + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function score() {
|
||||||
|
return (hasMinimumLength() ? 1 : 0) + (requireLowercase && hasLowercase() ? 1 : 0) + (requireUppercase && hasUppercase() ? 1 : 0) + (requireNumber && hasNumber() ? 1 : 0) + (requireSpecialCharacter && hasSpecialCharacter() ? 1 : 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
function maximumScore() {
|
||||||
|
return 1 + (requireLowercase ? 1 : 0) + (requireUppercase ? 1 : 0) + (requireNumber ? 1 : 0) + (requireSpecialCharacter ? 1 : 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
function strengthPercent() {
|
||||||
|
return Math.round(score() / maximumScore() * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
function strengthLevel() {
|
||||||
|
if (!password) {
|
||||||
|
return "empty"
|
||||||
|
}
|
||||||
|
if (strengthPercent() <= 25) {
|
||||||
|
return "weak"
|
||||||
|
}
|
||||||
|
if (strengthPercent() <= 50) {
|
||||||
|
return "fair"
|
||||||
|
}
|
||||||
|
if (strengthPercent() < 100) {
|
||||||
|
return "good"
|
||||||
|
}
|
||||||
|
return "strong"
|
||||||
|
}
|
||||||
|
|
||||||
|
function strengthLabel() {
|
||||||
|
if (strengthLevel() === "weak") {
|
||||||
|
return weakLabel
|
||||||
|
}
|
||||||
|
if (strengthLevel() === "fair") {
|
||||||
|
return fairLabel
|
||||||
|
}
|
||||||
|
if (strengthLevel() === "good") {
|
||||||
|
return goodLabel
|
||||||
|
}
|
||||||
|
if (strengthLevel() === "strong") {
|
||||||
|
return strongLabel
|
||||||
|
}
|
||||||
|
return emptyLabel
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
view {
|
||||||
|
<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}"
|
||||||
|
data-wrn-strong-password
|
||||||
|
data-strength="{password ? strengthLevel() : 'empty'}"
|
||||||
|
data-score="{password ? score() : 0}"
|
||||||
|
>
|
||||||
|
<label for="{name}-strong-password">{label}</label>
|
||||||
|
<div class="wire-next__strong-password-anchor">
|
||||||
|
<input
|
||||||
|
{...attrs}
|
||||||
|
id="{name}-strong-password"
|
||||||
|
type="password"
|
||||||
|
name="{name}"
|
||||||
|
value="{password}"
|
||||||
|
placeholder="{placeholder}"
|
||||||
|
autocomplete="{autocomplete}"
|
||||||
|
minlength="{minLength}"
|
||||||
|
disabled="{disabled}"
|
||||||
|
readonly="{readonly}"
|
||||||
|
required="{required}"
|
||||||
|
aria-invalid="{invalid ? 'true' : 'false'}"
|
||||||
|
aria-describedby="{validationMessage ? name + '-validation' : hintText ? name + '-hint' : ''}"
|
||||||
|
@focus="detailsOpen = true"
|
||||||
|
@blur="detailsOpen = false"
|
||||||
|
@input="password = event.target.value; $emit('input', { value: password, score: score(), maximumScore: maximumScore(), percent: strengthPercent(), level: strengthLevel() }); $emit('strength', { value: password, score: score(), maximumScore: maximumScore(), percent: strengthPercent(), level: strengthLevel() })"
|
||||||
|
@change="$emit('change', { value: password, score: score(), maximumScore: maximumScore(), percent: strengthPercent(), level: strengthLevel() })"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{#if presentation === "popover"}
|
||||||
|
<div
|
||||||
|
class="wire-next__strong-password-popover"
|
||||||
|
data-open="{detailsOpen ? 'true' : 'false'}"
|
||||||
|
role="status"
|
||||||
|
>
|
||||||
|
<div class="wire-next__strong-password-popover-arrow" aria-hidden="true"></div>
|
||||||
|
<div class="wire-next__strong-password-details">
|
||||||
|
<div class="wire-next__strong-password-summary">
|
||||||
|
<span>Password strength</span>
|
||||||
|
<strong>{password ? strengthLabel() : emptyLabel}</strong>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="wire-next__strong-password-meter"
|
||||||
|
role="progressbar"
|
||||||
|
aria-label="Password strength"
|
||||||
|
aria-valuemin="0"
|
||||||
|
aria-valuemax="100"
|
||||||
|
aria-valuenow="{password ? strengthPercent() : 0}"
|
||||||
|
>
|
||||||
|
<span style="width: {password ? strengthPercent() : 0}%"></span>
|
||||||
|
</div>
|
||||||
|
{#if showRequirements}
|
||||||
|
<ul class="wire-next__strong-password-requirements">
|
||||||
|
<li data-met="{password && hasMinimumLength() ? 'true' : 'false'}">
|
||||||
|
<span aria-hidden="true"></span>At least {minLength} characters
|
||||||
|
</li>
|
||||||
|
{#if requireLowercase}<li data-met="{password && hasLowercase() ? 'true' : 'false'}"><span aria-hidden="true"></span>One lowercase letter</li>{/if}
|
||||||
|
{#if requireUppercase}<li data-met="{password && hasUppercase() ? 'true' : 'false'}"><span aria-hidden="true"></span>One uppercase letter</li>{/if}
|
||||||
|
{#if requireNumber}<li data-met="{password && hasNumber() ? 'true' : 'false'}"><span aria-hidden="true"></span>One number</li>{/if}
|
||||||
|
{#if requireSpecialCharacter}<li data-met="{password && hasSpecialCharacter() ? 'true' : 'false'}"><span aria-hidden="true"></span>One special character: {specialCharactersSet}</li>{/if}
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
|
{#if hintText}<small id="{name}-hint">{hintText}</small>{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if presentation !== "popover"}
|
||||||
|
<div class="wire-next__strong-password-details">
|
||||||
|
<div class="wire-next__strong-password-summary">
|
||||||
|
<span>Password strength</span>
|
||||||
|
<strong>{password ? strengthLabel() : emptyLabel}</strong>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="wire-next__strong-password-meter"
|
||||||
|
role="progressbar"
|
||||||
|
aria-label="Password strength"
|
||||||
|
aria-valuemin="0"
|
||||||
|
aria-valuemax="100"
|
||||||
|
aria-valuenow="{password ? strengthPercent() : 0}"
|
||||||
|
>
|
||||||
|
<span style="width: {password ? strengthPercent() : 0}%"></span>
|
||||||
|
</div>
|
||||||
|
{#if showRequirements}
|
||||||
|
<ul class="wire-next__strong-password-requirements">
|
||||||
|
<li data-met="{password && hasMinimumLength() ? 'true' : 'false'}"><span aria-hidden="true"></span>At least {minLength} characters</li>
|
||||||
|
{#if requireLowercase}<li data-met="{password && hasLowercase() ? 'true' : 'false'}"><span aria-hidden="true"></span>One lowercase letter</li>{/if}
|
||||||
|
{#if requireUppercase}<li data-met="{password && hasUppercase() ? 'true' : 'false'}"><span aria-hidden="true"></span>One uppercase letter</li>{/if}
|
||||||
|
{#if requireNumber}<li data-met="{password && hasNumber() ? 'true' : 'false'}"><span aria-hidden="true"></span>One number</li>{/if}
|
||||||
|
{#if requireSpecialCharacter}<li data-met="{password && hasSpecialCharacter() ? 'true' : 'false'}"><span aria-hidden="true"></span>One special character: {specialCharactersSet}</li>{/if}
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
|
{#if hintText}<small id="{name}-hint">{hintText}</small>{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<small id="{name}-validation" class="wire-next__validation" data-error="{name}">{validationMessage}</small>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component StyledIcon {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Styled Icon"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--styled-icon 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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
component Tabs {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Tabs"
|
||||||
|
items = []
|
||||||
|
active = ""
|
||||||
|
orientation = "horizontal"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<nav class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--tabs wire-next--{orientation} {class}" aria-label="{label}">
|
||||||
|
{#each items as item}<a href="{item.href}" aria-current="{item.value === active ? 'page' : ''}">{item.label}</a>{/each}
|
||||||
|
<slot />
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
component TimePicker {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Time Picker"
|
||||||
|
name = ""
|
||||||
|
value = ""
|
||||||
|
placeholder = ""
|
||||||
|
type = "time"
|
||||||
|
min = ""
|
||||||
|
max = ""
|
||||||
|
step = ""
|
||||||
|
disabled = false
|
||||||
|
required = false
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--time-picker {class}"><span>{label}</span><input {...attrs} type="{type}" name="{name}" value="{value}" placeholder="{placeholder}" min="{min}" max="{max}" step="{step}" disabled="{disabled}" required="{required}" /></label>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Timeline {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Timeline"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<section class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--timeline wire-next--variant-{variant} {class}">
|
||||||
|
{#if title}<strong>{title}</strong>{/if}
|
||||||
|
{#if description}<p>{description}</p>{/if}
|
||||||
|
{#if items}<div class="wire-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component Toast {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Toast"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
component ToastNotifications {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
title = "Toast Notifications"
|
||||||
|
description = ""
|
||||||
|
items = []
|
||||||
|
variant = "default"
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
component ToggleCount {
|
||||||
|
props {
|
||||||
|
size = "default"
|
||||||
|
color = "primary"
|
||||||
|
label = "Toggle Count"
|
||||||
|
name = ""
|
||||||
|
value = ""
|
||||||
|
placeholder = ""
|
||||||
|
type = "text"
|
||||||
|
min = ""
|
||||||
|
max = ""
|
||||||
|
step = ""
|
||||||
|
disabled = false
|
||||||
|
required = false
|
||||||
|
class = ""
|
||||||
|
}
|
||||||
|
view {
|
||||||
|
<label class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--field wire-next--toggle-count {class}"><span>{label}</span><input {...attrs} type="{type}" name="{name}" value="{value}" placeholder="{placeholder}" min="{min}" max="{max}" step="{step}" disabled="{disabled}" required="{required}" /></label>
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user