# SlexKit Full LLM Documentation Version: 0.4.0 This file concatenates SlexKit's canonical English Markdown docs. `slex` fences are preserved exactly. # README URL: / Raw Markdown: /README.md Source: README.md

SlexKit

SlexKit

Streaming Live EXpressions Kit

"Docs as tools, tools as docs." Render explicit Markdown fences as live, stateful UI blocks.

Documentation · Components · Specification · AI / Agents · 简体中文

version script TypeScript Svelte 5 license

SlexKit renders explicit slex Markdown fences as live interactive UI blocks

## Live interface blocks inside Markdown **SlexKit** turns explicit `slex` Markdown fences into live, stateful UI blocks. A Slex source is just a JavaScript object literal: `g` holds state and logic, `layout` describes the component tree, and the browser runtime renders the result in place. It is built for chat messages, documents, agent panels, tool results, and AI-authored dashboards. It is not a full application framework. ## Installation > Just want to use SlexKit in Obsidian? Open **Settings -> Community plugins**, search for **SlexKit**, then install and enable it. The npm package below is for developers integrating SlexKit into web apps, Markdown renderers, Streamdown, or custom hosts. ```sh npm install slexkit ``` ```ts import { mount } from "slexkit"; import "slexkit/style.css"; ``` ## Usage ```html
``` ## Markdown Native SlexKit-capable hosts process explicit `slex` fences only. Plain `js`, `json`, and unlabeled code blocks stay inert. ````md ```slex { slex: "0.1", namespace: "status", g: { done: 3, total: 4 }, layout: { "badge:state": { label: "Ready", tone: "success" }, "text:summary": { "$text": "g.done + '/' + g.total + ' complete'" } } } ``` **Status:** Ready. 3/4 complete. ```` Markdown platforms without SlexKit support show the fallback text. Hosts with SlexKit render the interactive UI. ## What You Get - **Zero-build Slex source**: object literals with no imports, scaffolding, or component bundling in the generated output. - **Reactive `g` / `layout` model**: centralized state and logic with declarative component trees. - **Expression pipes**: `$` read expressions for dynamic props and `on*` write expressions for events. - **Directives**: `$if` and `$for` for conditional rendering and keyed list reconciliation. - **Official Svelte components**: 30 components across layout, input, content, display, disclosure, feedback, and tooling. - **Extensible registry**: custom component types, Svelte renderers, and component state modes. - **Trusted and secure runtimes**: host-realm rendering for trusted content, sandbox iframe rendering for untrusted source. - **ToolHost**: confirm, choose, and fill-form templates for structured AI tool-call UX. - **AI-friendly docs surface**: `llms.txt`, skills, and the `@slexkit/mcp` read-only MCP server. ## Packages | Package | Install | Contents | | --- | --- | --- | | `slexkit` | `npm install slexkit` | Runtime, Svelte components, ToolHost, styles | | `@slexkit/runtime` | `npm install slexkit @slexkit/runtime` | Component-free runtime wrapper | | `@slexkit/components-svelte` | `npm install slexkit @slexkit/runtime @slexkit/components-svelte` | Svelte component registration | | `@slexkit/theme-shadcn` | `npm install @slexkit/theme-shadcn` | CSS theme tokens | | `@slexkit/streamdown` | `npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown streamdown react react-dom` | React / Streamdown Markdown renderer | | `@slexkit/assistant-ui` | `npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown @slexkit/assistant-ui @assistant-ui/react @assistant-ui/react-streamdown streamdown react react-dom` | assistant-ui message text wrapper for `slex` fences | | `@slexkit/tiptap` | `npm install slexkit @slexkit/theme-shadcn @slexkit/tiptap @tiptap/core @tiptap/pm @tiptap/starter-kit @tiptap/extension-code-block @tiptap/markdown` | Tiptap code block NodeView for `slex` fences | | `@slexkit/mcp` | `npx -y @slexkit/mcp` | Read-only MCP server for docs, examples, and source validation | See [Packages](site/content/reference/packages/en-US.md) for details. ## Integrations | Host | Path | | --- | --- | | Browser DOM | `mount()`, `ingest()`, `boot()`, `disposeNamespace()` | | Markdown renderers | `createSlexKitMarkdownRuntimeHost()` | | assistant-ui | `@slexkit/assistant-ui` | | React / Streamdown | `@slexkit/streamdown` | | Tiptap | `@slexkit/tiptap` | | Obsidian | Install **SlexKit** from Community Plugins; release repo: | | AI agents | `@slexkit/mcp`, `llms.txt`, SlexKit skill docs | | Custom components | `register()`, `registerSvelteComponent()`, `registerSubset()` | ## Security Runtime Trusted mode runs inside the host realm and is intended for application-authored or reviewed source. Secure mode isolates untrusted Slex source in a sandbox iframe with an opaque origin, nonce-based CSP, locked-down globals, host-mediated network access, and a heartbeat watchdog. Read the [Security Runtime](site/content/reference/security/en-US.md) docs before rendering unreviewed user or model output. ## Documentation | Document | Topic | | --- | --- | | [Getting Started](site/content/guides/quick-start/en-US.md) | Install and render a first Markdown-friendly Slex source | | [Integration](site/content/guides/integration/en-US.md) | Streamdown, Tiptap, Obsidian, and custom host paths | | [Runtime model](site/content/reference/runtime/en-US.md) | Mounting, updates, namespace store, lifecycle | | [Slex usage reference](site/content/reference/usage/en-US.md) | Source structure, directives, expressions, events, custom components | | [Security runtime](site/content/reference/security/en-US.md) | Threat model, sandbox iframe, policy, postMessage bridge | | [Slex Specification](site/content/reference/spec/en-US.md) | Protocol v0.1, types, merge rules, lifecycle hooks | | [ToolHost](site/content/reference/toolhost/en-US.md) | Tool-call rendering and custom templates | | [Icon system](site/content/reference/icons/en-US.md) | Phosphor icons, custom registration, Iconify fallback | | [AI / Agents](site/content/guides/ai-agents/en-US.md) | `llms.txt`, MCP server, skills, and authoring rules | | [Changelog](CHANGELOG.md) | Release notes and notable changes | ## Version Information ```ts import { SLEXKIT_VERSION, SLEX_PROTOCOL_VERSION, getSlexKitInfo } from "slexkit"; ``` The npm package version, component implementation version, and Slex protocol version are exposed separately. The current public protocol is `v0.1`. ## License MIT --- # SlexKit Introduction URL: /docs/guides/intro Raw Markdown: /docs/guides/intro.md Source: site/content/guides/intro/en-US.md --- title: SlexKit Introduction category: Guides status: ready order: 10 summary: "Markdown-friendly reactive UI runtime for explicit slex fences." slexkitRenderMode: component --- # SlexKit Introduction SlexKit renders Markdown fences marked as `slex` into small interactive UI. Use it for local interaction inside chat messages, documents, agent panels, and dashboards without adding a build step for those fragments. SlexKit is v0/beta. The public surface is usable, but long-term compatibility is not yet guaranteed. ## When To Use It When Markdown needs a small amount of interaction: - Status cards, counters, calculators, parameter panels, lightweight dashboards - AI-generated UI fragments that should degrade to plain Markdown - React, Svelte, Obsidian, or vanilla HTML hosts rendering the same fenced source SlexKit is not a full application framework. It does not provide routing, server-side rendering, a data fetching layer, or a cross-platform pure JSON UI standard. ## Source Format A Slex source is a JavaScript object literal with state in `g` and the component tree in `layout`: ```slex { namespace: "intro_counter", g: { count: 0 }, layout: { "card:counter": { title: "Counter", "text:value": { "$text": "'Count: ' + g.count" }, "button:add": { label: "+1", onclick: "g.count++" } } } } ``` - `namespace` identifies the state domain - `g` contains reactive state, functions, and small calculations - `layout` contains component nodes keyed as `type:name` - `$`-prefixed props are read expressions, such as `"$text": "'Count: ' + g.count"` - `on*` props are write expressions, such as `onclick: "g.count++"` The runtime also accepts a bare component tree as shorthand, but the full envelope is preferred for documentation and shared examples. ## Fence Convention Hosts must process only fences explicitly marked as `slex`: ````md ```slex { namespace: "status", layout: { "badge:state": { label: "Ready", tone: "success" } } } ``` **Status:** Ready ```` The Markdown after the fence is the fallback. Plain Markdown readers show the fallback text; SlexKit-capable hosts replace the fence with interactive UI. Plain JavaScript, JSON, or untagged code blocks must not be scanned or executed. ## Runtime Modes **Trusted mode** executes Slex source in the host page. Use it for application-generated content, local documents, and repository-maintained examples. **Secure mode** executes untrusted or agent-generated source in a sandbox iframe. Sensitive capabilities such as network, timers, animation, and canvas are exposed only through host policy and `api.*`. Use secure mode when rendering third-party or unreviewed content. See [Secure Runtime Setup](security-runtime). ## Display UI And Tool Calls **Display UI** renders via `slex` fences or `mount()`. These fragments show information and local interaction but are not function calls. **ToolHost** is for confirmations, option pickers, and forms that must return structured input to the host. The `submit` component ends a tool template and submits the result. This separation prevents ordinary display UI from being mispackaged as tool invocations. ## Core APIs | API | Use | |---|---| | `mount(input, container, options?)` | Render trusted Slex source into a container | | `ingest(input)` | Merge state-only source without rendering UI | | `boot(options?)` | Enhance static page `slex` fences | | `createSlexKitMarkdownRuntimeHost(options?)` | Recommended API for Markdown hosts | | `mountSecureArtifact(input, container, options)` | Render source in the secure sandbox runtime | | `renderToolCall(call, container)` | Render a ToolHost template and collect a result | Type details and beta compatibility notes are in the [Slex Specification](/docs/reference/spec). ## Keep Reading - [Getting Started](quick-start): developer integration path - [Integration](integration): Streamdown and Obsidian host plugins - [Design Guidelines](design): authoring public examples and component usage - [Secure Runtime Setup](security-runtime): untrusted content boundary - [Component Reference](../components/card): built-in component catalog - [AI / Agents](ai-agents): SlexKit context for models and agents --- # Quick Start URL: /docs/guides/quick-start Raw Markdown: /docs/guides/quick-start.md Source: site/content/guides/quick-start/en-US.md --- title: Getting Started category: Guides status: ready order: 20 summary: "Install SlexKit, mount a first fragment, and keep readable Markdown fallback." slexkitRenderMode: component --- # Getting Started > For Obsidian plugin installation, open **Settings -> Community plugins**, search for **SlexKit**, then install and enable it. The npm package path below targets web apps, Markdown hosts, Streamdown, and custom runtimes. Start by installing `slexkit` and mounting a trusted fragment. Once basic rendering works, move on to Markdown hosts, Streamdown, or the Obsidian plugin. ## Installation Entry For most apps, start by installing the root package: ```sh npm install slexkit ``` ```ts import { mount } from "slexkit"; import "slexkit/style.css"; ``` For host-specific packages, choose by scenario: | Use case | Install | |---|---| | Custom components or component-free runtime | `npm install slexkit @slexkit/runtime` | | Official Svelte component registration | `npm install slexkit @slexkit/runtime @slexkit/components-svelte` | | Standalone shadcn-token theme CSS | `npm install @slexkit/theme-shadcn` | | React + Streamdown Markdown host | `npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown streamdown react react-dom` | | Obsidian vault rendering | Install **SlexKit** from Obsidian Community Plugins | `@slexkit/runtime` and `@slexkit/components-svelte` wrap the root package; they are not independent implementations. ## Trusted Fragment Start with trusted mode for application-authored source, local examples, repository examples, and reviewed snippets. ```ts import { mount } from "slexkit"; import "slexkit/style.css"; const source = { namespace: "getting_started_counter", g: { count: 0 }, layout: { "card:demo": { title: "Counter", "text:value": { "$text": "'Count: ' + g.count" }, "button:add": { label: "+1", onclick: "g.count++" } } } }; const cleanup = mount(source, document.getElementById("app")!); ``` Call `cleanup()` when removing containers, replacing messages, or unloading pages. If the namespace won't be reused, call `disposeNamespace(namespace)`. ## Markdown Fallback When source appears in Markdown, handle only explicit `slex` fences and keep readable fallback text after the fence: ````md ```slex { namespace: "release_status", layout: { "badge:status": { label: "Ready", tone: "success" }, "text:summary": { text: "3 of 3 checks passed." } } } ``` **Release status:** Ready. 3 of 3 checks passed. ```` SlexKit-capable hosts render the fence. Plain Markdown hosts show the fallback. Do not infer executable SlexKit source from `js`, `json`, or unlabeled code blocks. ## Markdown Host For chat messages, docs pages, or long Markdown content, use `createSlexKitMarkdownRuntimeHost`. It lets multiple `slex` blocks in one document share state and provides one place for cleanup and trusted/secure mode selection. ```ts import { createSlexKitMarkdownRuntimeHost } from "slexkit"; import "slexkit/style.css"; const runtime = createSlexKitMarkdownRuntimeHost({ mode: "trusted", theme: "host-shadcn" }); export function mountSlexFence(source: string, container: HTMLElement) { return runtime.mountBlock({ artifactId: "message-42", source, container }); } ``` When the whole document or message thread is destroyed, call `runtime.disposeArtifact(artifactId)` or `runtime.disposeAll()`. ## Content Source | Content source | Use | |---|---| | App-generated source, repository examples, local vault content | trusted | | Unreviewed user input, third-party Markdown, direct agent output | secure | Secure mode requires a sandbox iframe, a publicly served `slexkit.runtime.js`, and a host policy. See [Secure Runtime Setup](security-runtime). ## Keep Reading - [Integration](integration): React/Streamdown and Obsidian plugins - [Secure Runtime Setup](security-runtime): untrusted or agent-generated content - [Component Reference](../components/card): built-in component catalog - [AI / Agents](ai-agents): SlexKit authoring context for models and agents --- # Integration URL: /docs/guides/integration Raw Markdown: /docs/guides/integration.md Source: site/content/guides/integration/en-US.md --- title: Integration category: Guides status: ready order: 25 summary: "Connect SlexKit to assistant-ui, Streamdown, Tiptap, Obsidian, or a custom Markdown renderer." slexkitRenderMode: component --- # Integration Choose the right SlexKit host integration by matching where Markdown is rendered. Every integration renders only fenced code blocks whose language is `slex`; ordinary `js`, `json`, and unlabeled code blocks stay with the host Markdown renderer. For the full host API, see the [Host Integration reference](/docs/reference/integration). ## Choose An Integration | Host | Install or enable | Render target | Default mode | |---|---|---|---| | assistant-ui | `@slexkit/assistant-ui` | text message parts | secure | | React / Streamdown | `@slexkit/streamdown` | chat messages and React Markdown pages | trusted or secure | | Tiptap | `@slexkit/tiptap` | `slex` code block previews in an editor | trusted | | Obsidian | **SlexKit** from Community Plugins | local notes in reading mode | trusted readonly | | Custom Markdown host | `slexkit` | product docs, document viewers, site renderers | trusted or secure | assistant-ui, Streamdown, and Tiptap have ready-made packages. Custom Markdown renderers can use `createSlexKitMarkdownRuntimeHost` directly. The Obsidian plugin can be installed from Community Plugins; use the [plugin repository](https://github.com/slexkit/obsidian-slexkit) only when testing unreleased builds. Package exports and install combinations are listed in [Packages](/docs/reference/packages). ## Runnable Examples Runnable examples show the integration behavior before app wiring. Streamdown and Tiptap use the same RC low-pass Markdown source, so read-only rendering and editor preview can be compared directly: - [Streamdown Host Adapter](/examples/streamdown-host) mirrors `examples/streamdown`. - [Tiptap Editor Adapter](/examples/tiptap-host) mirrors `examples/tiptap`. - [assistant-ui Adapter](/examples/assistant-ui-host) mirrors `examples/assistant-ui`. ## Svelte Markdown Host The SlexKit website uses a custom Markdown renderer inside a Svelte app. There is no separate Svelte Markdown adapter package. When an app owns Markdown parsing, hand each `slex` code block to SlexKit like this: ```js import { createSlexKitMarkdownRuntimeHost } from "slexkit"; import MarkdownRenderer from "./MarkdownRenderer.svelte"; const runtimeHost = createSlexKitMarkdownRuntimeHost({ mode: "trusted", theme: "host-shadcn" }); mount(MarkdownRenderer, { target: container, props: { content: markdown, artifactId: "docs-page", runtimeHost, slexkitRenderMode: "component" } }); ``` Use this pattern when the product owns the Markdown parser, Svelte component tree, or document shell. Keep three rules in place: detect only `slex` fences, pass a stable `artifactId` for the document, and call cleanup when the rendered document unmounts. ## Streamdown Install the runtime, theme, plugin, and React peer dependencies: ```sh npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown streamdown react react-dom ``` Import styles once in the app entry: ```ts import "@slexkit/theme-shadcn/style.css"; import "@slexkit/streamdown/style.css"; ``` Register the renderer with Streamdown: ```tsx import { Streamdown } from "streamdown"; import { slexkitRenderer } from "@slexkit/streamdown"; export function Message({ markdown }: { markdown: string }) { return ( {markdown} ); } ``` This renderer only replaces `slex` code blocks. Other code blocks stay with Streamdown. ## assistant-ui When an assistant-ui app already renders text through `@assistant-ui/react-streamdown`, use the SlexKit wrapper for message text parts: ```sh npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown @slexkit/assistant-ui @assistant-ui/react @assistant-ui/react-streamdown streamdown react react-dom ``` Import styles once in the app entry: ```ts import "@slexkit/theme-shadcn/style.css"; import "@slexkit/assistant-ui/style.css"; ``` Use the wrapper where assistant-ui renders text message parts: ```tsx import { MessagePrimitive } from "@assistant-ui/react"; import { SlexKitAssistantStreamdownText } from "@slexkit/assistant-ui"; export function AssistantMessage() { return ( {({ part }) => part.type === "text" ? ( ) : null } ); } ``` The wrapper only replaces the `slex` language block. Threads, composer state, message state, tool calls, approvals, and form submissions stay with the existing assistant-ui or ToolHost layer. ## Tiptap Install the SlexKit adapter, theme, and Tiptap dependencies: ```sh npm install slexkit @slexkit/theme-shadcn @slexkit/tiptap @tiptap/core @tiptap/pm @tiptap/starter-kit @tiptap/extension-code-block @tiptap/markdown ``` Import styles once in the app entry: ```ts import "@slexkit/theme-shadcn/style.css"; import "@slexkit/tiptap/style.css"; ``` Disable StarterKit's default code block, then register the SlexKit extension: ```ts import { Editor } from "@tiptap/core"; import StarterKit from "@tiptap/starter-kit"; import { Markdown } from "@tiptap/markdown"; import { createSlexKitTiptapExtension } from "@slexkit/tiptap"; const editor = new Editor({ element: document.querySelector("#editor"), extensions: [ StarterKit.configure({ codeBlock: false }), Markdown, createSlexKitTiptapExtension({ artifactId: "doc-1" }) ], content: markdown, contentType: "markdown" }); ``` The extension only takes over code blocks whose language is exactly `slex`. Other code blocks remain normal editable Tiptap code blocks. All `slex` blocks in one editor share state: a state-only block can seed a later layout block. The Tiptap integration uses trusted mode by default; render unreviewed user Markdown or third-party content in a secure web host instead. ## Streamdown Options Use `createSlexKitRenderer` to set the message/domain, hide source, enable playground behavior, or switch to secure mode: ```tsx import { createSlexKitRenderer } from "@slexkit/streamdown"; const renderer = createSlexKitRenderer({ domain: "chat-thread-42", showChrome: false, showSource: false, runtime: "trusted" }); ``` Inside the same `domain`, an earlier state-only block can provide data for a later layout block: ````md ```slex { namespace: "calc", g: { value: 21 } } ``` ```slex { namespace: "calc", layout: { "text:answer": { "$text": "'answer: ' + (g.value * 2)" } } } ``` ```` For unreviewed user input, third-party Markdown, or direct agent output, switch to secure mode: ```tsx const renderer = createSlexKitRenderer({ runtime: "secure", secureFrame: { runtimeUrl: "/slexkit.runtime.js" }, securePolicy: { execution: { maxUnresponsiveMs: 30000 } } }); ``` Use [Secure Runtime Setup](security-runtime) and the [Security Runtime Contract](/docs/reference/security) when deploying the sandbox iframe, runtime file, and policy fields. ## Obsidian > For Obsidian plugin installation only, the developer integration material above is unnecessary. Search for **SlexKit** in Obsidian **Community plugins**, then install and enable it. The Obsidian plugin renders `slex` code blocks from your local vault in reading mode. It does not write rendered output back to notes. Install the plugin from Obsidian Community Plugins: 1. Open **Settings -> Community plugins**. 2. Disable **Restricted mode** if needed. 3. Search for **SlexKit**. 4. Install and enable the plugin. The community plugin is marked desktop-only and compatible with Obsidian 1.5.0+. To test an unreleased build, use BRAT: ```text BRAT repository: https://github.com/slexkit/obsidian-slexkit ``` Manual installs copy the GitHub release assets into the vault: ```text .obsidian/plugins/slexkit/ main.js manifest.json styles.css ``` Enable **SlexKit** in Obsidian's community plugin settings. ## Obsidian Example Write an explicit `slex` fence in a note: ````md ```slex { namespace: "vault_status", layout: { "card:status": { title: "Vault status", "badge:ready": { label: "Ready", tone: "success" }, "text:note": { text: "Rendered by SlexKit in reading mode." } } } } ``` Vault status: Ready. ```` `slex` code blocks in the same note share state, so an earlier state block can affect a later rendered block. ## Obsidian Security Notes The official plugin treats local vault content as trusted. It is not a sandbox for third-party Markdown or direct agent output. For untrusted content, use secure mode in a web host with a sandbox frame and host policy. ## Before You Ship - Process only fences whose language is exactly `slex` - Keep Markdown fallback for environments without SlexKit - Use a stable artifact/domain for each document, message, or note - Call cleanup when a container unmounts; dispose the artifact when the document is destroyed - Use secure mode for untrusted content instead of trusted mode --- # Design Guidelines URL: /docs/guides/design Raw Markdown: /docs/guides/design.md Source: site/content/guides/design/en-US.md --- title: Design Philosophy category: Guides status: ready order: 30 summary: "Design principles for live Markdown, components, and agent-generated UI." includeTitleInToc: true slexkitRenderMode: component --- # SlexKit Design Philosophy **Docs as tools, tools as docs.** Static documents can embed interactive components, and agent output can carry structured UI. ```slex { namespace: "design_philosophy", layout: { "diagram:philosophy": {}, "grid:philosophy": { columns: 1, lgColumns: 3, "card:task": { tone: "primary", "heading:title": { level: 4, title: "Task-First" }, "text:bodyA": { text: "Start from the task the user needs to complete." }, "text:bodyB": { text: "Every design decision serves the core task." } }, "card:intuitive": { tone: "info", "heading:title": { level: 4, title: "Intuitive" }, "text:bodyA": { text: "Docs include live examples that update instantly." }, "text:bodyB": { text: "Data flows across components through scoped binding." } }, "card:breath": { tone: "success", "heading:title": { level: 4, title: "Visual Breath" }, "text:bodyA": { text: "Whitespace and spacing create visual rhythm." }, "text:bodyB": { text: "Typography and color build clear hierarchy." } } } } } ``` ## Color Semantics Color expresses role, not personal preference. ```slex { namespace: "design_color", layout: { "grid:colors": { columns: 1, mdColumns: 2, lgColumns: 3, "card:primary": { tone: "primary", "swatch:primary": { tone: "primary" }, "heading:title": { level: 4, title: "Primary" }, "text:body": { text: "Main actions, current selection, high-priority emphasis. Do not use as decoration." } }, "card:info": { tone: "info", "swatch:info": { tone: "info" }, "heading:title": { level: 4, title: "Info" }, "text:body": { text: "Guidance, hints, informational states. Do not replace Primary." } }, "card:success": { tone: "success", "swatch:success": { tone: "success" }, "heading:title": { level: 4, title: "Success" }, "text:body": { text: "Completed, passed, safe to continue. Use only when the result is confirmed." } }, "card:warning": { tone: "warning", "swatch:warning": { tone: "warning" }, "heading:title": { level: 4, title: "Warning" }, "text:body": { text: "Risk, threshold, needs attention but not failed. Do not use to brighten pages." } }, "card:destructive": { tone: "destructive", "swatch:destructive": { tone: "destructive" }, "heading:title": { level: 4, title: "Destructive" }, "text:body": { text: "Errors, deletions, irreversible actions. Must include consequence description." } }, "card:neutral": { tone: "neutral", "swatch:neutral": { tone: "neutral" }, "heading:title": { level: 4, title: "Neutral" }, "text:body": { text: "Backgrounds, dividers, secondary information, default containers. Provides structure, not emphasis." } } } } } ``` ## Card Arrangement Small cards are for comparison and judgment. Run metrics side-by-side; the system handles equal width, spacing, and wrapping. Wrap in a parent card when items share context; stack vertically when order matters. ```slex { namespace: "design_arrangement", layout: { "column:arrange": { "row:metrics": { "stat:requests": { label: "Requests", value: "1.2k", unit: "/min", tone: "info" }, "stat:success": { label: "Success", value: "98.4", unit: "%", tone: "success" }, "stat:latency": { label: "Latency", value: "42", unit: "ms" }, "stat:errors": { label: "Errors", value: "3", tone: "warning" }, "stat:queued": { label: "Queued", value: "8" } }, "grid:examples": { columns: 1, mdColumns: 2, "card:summary": { title: "Same Object", "row:service": { "stat:idle": { label: "Pending", value: "12" }, "stat:active": { label: "Running", value: "5", tone: "info" }, "stat:done": { label: "Done", value: "47", tone: "success" }, "stat:failed": { label: "Failed", value: "2", tone: "danger" } } }, "card:flow": { title: "Sequential", "column:steps": { "stat:input": { label: "Input", value: "1" }, "stat:compute": { label: "Compute", value: "2", tone: "info" }, "stat:output": { label: "Output", value: "3", tone: "success" } } } } } } } ``` ## Typography & Icons SlexKit's typography is calm, clear, and technical. Icons are light, rounded, and restrained — serving as punctuation marks in the interface, not illustrations. ```slex { namespace: "design_type_icon", layout: { "grid:type": { columns: 1, lgColumns: 2, "card:type": { "heading:title": { level: 4, title: "Type Voice", meta: "GEIST / NOTO SANS SC" }, "diagram:font": { kind: "font-sample" }, "text:body": { text: "English uses Geist, Chinese uses Noto Sans SC. Letterforms stay open and clean, serving readability rather than volume." } }, "card:icon": { "heading:title": { level: 4, title: "Icon Voice", meta: "PHOSPHOR ICONS" }, "row:icons": { "button:sparkle": { icon: "sparkle", iconOnly: true, label: "Assist" }, "button:book": { icon: "book-open-text", iconOnly: true, label: "Manual" }, "button:terminal": { icon: "terminal-window", iconOnly: true, label: "Terminal" }, "button:cursor": { icon: "cursor-click", iconOnly: true, label: "Click" }, "button:nut": { icon: "nut", iconOnly: true, label: "Nut" }, "button:gear": { icon: "gear-six", iconOnly: true, label: "Gear" } }, "text:body": { text: "Phosphor's character comes from geometric outlines, rounded corners, and consistent stroke width. When choosing icons, first check tone consistency, then semantic accuracy." } } } } } ``` ## Markdown Authoring Design specs and component pages use Markdown for prose, with `slex` fenced blocks for runnable examples, achieving docs-as-examples authoring. ```slex { namespace: "design_markdown", layout: { "grid:doc": { columns: 1, lgColumns: 3, "card:write": { "diagram:markdown": {}, "heading:title": { level: 4, title: "Prose in Markdown" }, "text:body": { text: "Explain context, boundaries, and rules. Do not write explanations inside UI components." } }, "card:run": { "diagram:fence": {}, "heading:title": { level: 4, title: "Examples in slex" }, "text:body": { text: "Every key example should render and preview live, not be a screenshot." } }, "card:compare": { "diagram:cards": {}, "heading:title": { level: 4, title: "Rules as Small Cards" }, "text:body": { text: "Put comparable principles into cards so readers can judge at a glance." } } } } } ``` ## Product Shape SlexKit is for interactive fragments inside Markdown, not full applications. Typical scenarios include: - A card explaining a result - A row of metrics - A form-like control area - A status or confirmation block The framework focuses on embedded document interactions, not routing, global app state, SSR, data fetching frameworks, or general UI standardization. ```slex { namespace: "design_shape", layout: { "card:status": { title: "Build summary", tone: "info", "row:metrics": { "stat:passed": { label: "Passed", value: 28, tone: "success" }, "stat:failed": { label: "Failed", value: 1, tone: "danger" }, "stat:queued": { label: "Queued", value: 3, tone: "muted" } }, "text:note": { text: "Keep the surface focused on one document or message task." } } } } ``` ## Tone Rules Components support semantic tone values for expressing state roles. ```slex { namespace: "design_tones", layout: { "grid:tones": { columns: 1, mdColumns: 2, lgColumns: 3, "card:info": { tone: "info", "badge:tone": { label: "info", tone: "info" }, "text:body": { text: "Neutral guidance, current process, or informational state." } }, "card:success": { tone: "success", "badge:tone": { label: "success", tone: "success" }, "text:body": { text: "Completed, accepted, or safe-to-continue state." } }, "card:warning": { tone: "warning", "badge:tone": { label: "warning", tone: "warning" }, "text:body": { text: "Risk, threshold, or review-needed state." } }, "card:danger": { tone: "danger", "badge:tone": { label: "danger", tone: "danger" }, "text:body": { text: "Error, destructive action, or blocked state." } }, "card:muted": { tone: "muted", "badge:tone": { label: "muted", tone: "muted" }, "text:body": { text: "Secondary or background information." } } } } } ``` ## Display UI Versus ToolHost Display UI is for information presentation and local interaction. ToolHost mode is used when the host needs structured results from the user. ```slex { namespace: "design_boundary", layout: { "grid:boundary": { columns: 1, mdColumns: 2, "card:display": { tone: "muted", title: "Display UI", "text:body": { text: "Use slex fences for status, metrics, previews, and local controls." }, "badge:kind": { label: "No host result", tone: "muted" } }, "card:toolhost": { tone: "info", title: "ToolHost", "text:body": { text: "Use tool templates when confirmation or form data must return to the host." }, "badge:kind": { label: "Returns ToolResult", tone: "info" } } } } } ``` --- # Secure Runtime Setup URL: /docs/guides/security-runtime Raw Markdown: /docs/guides/security-runtime.md Source: site/content/guides/security-runtime/en-US.md --- title: Secure Runtime Setup category: Guides status: ready order: 40 summary: "Use secure mode for unreviewed user input, third-party Markdown, or agent output." slexkitRenderMode: component --- # Secure Runtime Setup Use secure mode when the host does not fully control the Slex source: unreviewed user input, third-party Markdown, direct agent output, or shared documents where authorship is unclear. Secure mode needs both deployment and policy setup. The threat model, `HostRuntimePolicy`, sandbox attributes, bridge messages, and fail-closed behavior are covered in the [Security Runtime Contract](/docs/reference/security). ## When To Use Secure Mode | Source | Use | Notes | |---|---|---| | Application-generated source | trusted | The source is created by the app. | | Repository examples or reviewed snippets | trusted | Keep examples explicit and versioned. | | Local Obsidian vault notes | trusted readonly | The Obsidian plugin does not provide sandbox isolation. | | User-submitted Markdown | secure | Treat source as untrusted even when the Markdown looks harmless. | | Direct agent output | secure | Do not grant network, timer, animation, or canvas access by default. | If the answer is unclear, start with secure mode and enable capabilities only after the host has a concrete product need. ## Minimal Host Setup For Markdown hosts, prefer `createSlexKitMarkdownRuntimeHost`. It lets multiple `slex` blocks in one document share state, and it keeps block cleanup and secure-frame mounting in one place. ```ts import { createSlexKitMarkdownRuntimeHost } from "slexkit"; import "slexkit/style.css"; const runtime = createSlexKitMarkdownRuntimeHost({ mode: "secure", theme: "host-shadcn", secureFrame: { runtimeUrl: "/slexkit.runtime.js" }, policy: { execution: { heartbeatIntervalMs: 1000, maxUnresponsiveMs: 30000 } } }); export function mountSlexFence(source: string, container: HTMLElement) { return runtime.mountBlock({ artifactId: "message-42", source, container }); } ``` Call `disposeBlock(container)` when a fence disappears, and call `disposeArtifact(artifactId)` when the full message, document, or note is destroyed. Omitted capability policies deny access by default. Add `network`, `timer`, `animation`, or `canvas` policy objects only when the host intentionally enables those capabilities. ## Runtime Module The secure iframe imports the runtime from `secureFrame.runtimeUrl`. Serve that file as a public ES module: ```http Access-Control-Allow-Origin: * Content-Type: text/javascript ``` This is server or deployment configuration. It cannot be repaired from frontend JavaScript after the request has already failed. ## Policy Settings - Keep network disabled unless a specific product feature needs it. - If network is enabled, allow only required methods, origins, headers, body sizes, response sizes, and content types. - Keep timers, animation, and canvas disabled unless the Slex source needs them. - Never treat `capabilities`, `permissions`, `api`, or similar fields inside Slex source as authorization. - Do not add `allow-same-origin` to solve CORS or debugging issues. - Keep unresponsive runtime failures visible through the built-in fail-closed diagnostic. Policy fields and allowed adapter hooks are listed in the [Security Runtime Contract](/docs/reference/security). ## Host Notes `@slexkit/streamdown` can run trusted or secure. Use secure mode for chat messages and agent output unless the message source is already trusted by the host. The official Obsidian plugin treats local vault content as trusted. Do not use it to isolate third-party Markdown or direct agent output. Custom Markdown hosts should still process only fences whose language is exactly `slex` and should preserve readable Markdown fallback for non-SlexKit environments. ## Production Checklist - Stable `artifactId` per message, document, or note - Explicit `slex` fence detection only - Public `slexkit.runtime.js` module with CORS and JavaScript content type - Deny-by-default host policy - Cleanup on block removal and artifact destruction - Visible fallback text after each interactive fence - Policy, bridge, CSP, and sandbox details have been checked --- # AI / Agents URL: /docs/guides/ai-agents Raw Markdown: /docs/guides/ai-agents.md Source: site/content/guides/ai-agents/en-US.md --- title: AI / Agents category: Guides status: ready order: 50 summary: "LLM docs, MCP server, skills, and authoring rules for SlexKit agents." slexkitRenderMode: component --- # AI / Agents ## AI Accessible Documentation SlexKit exposes AI-facing documentation as a small set of predictable entry points: a clear index, a full-context file, task-oriented skills, and a minimal MCP surface. Raw docs stay as `.md` pages, and interactive examples use explicit `slex` fences. ```slex { namespace: "ai_docs_links", layout: { "column:links": { gap: "sm", "link:index": { href: "/llms.txt", text: "/llms.txt - docs index", icon: "list-magnifying-glass" }, "link:full": { href: "/llms-full.txt", text: "/llms-full.txt - full English context", icon: "book-open-text" }, "link:components": { href: "/llms-components.txt", text: "/llms-components.txt - components and API", icon: "puzzle-piece" }, "link:runtime": { href: "/llms-runtime.txt", text: "/llms-runtime.txt - runtime and host integration", icon: "cpu" }, "link:capabilities": { href: "/llms-capabilities.txt", text: "/llms-capabilities.txt - std and api capabilities", icon: "function" }, "link:toolhost": { href: "/llms-toolhost.txt", text: "/llms-toolhost.txt - structured input", icon: "cursor-click" }, "link:authoring": { href: "/llms-authoring.txt", text: "/llms-authoring.txt - slex fence authoring rules", icon: "pencil-simple" }, "link:manifest": { href: "/slexkit-ai-manifest.json", text: "/slexkit-ai-manifest.json - machine-readable index", icon: "brackets-curly" }, "link:standard": { href: "/standard/slex-standard-manifest.json", text: "/standard/slex-standard-manifest.json - standard artifacts", icon: "brackets-curly" }, "link:catalog": { href: "/standard/slex-component-catalog.json", text: "/standard/slex-component-catalog.json - component catalog", icon: "puzzle-piece" }, "link:logic": { href: "/standard/slex-logic-profile.json", text: "/standard/slex-logic-profile.json - logic profile", icon: "function" }, "link:conformance": { href: "/standard/slex-conformance.json", text: "/standard/slex-conformance.json - conformance fixtures", icon: "check-circle" }, "text:note": { text: "Raw docs use .md routes such as /docs/components/card.md. Do not add .mdx routes." } } } } ``` Minimal reading path: 1. Start with [`/llms.txt`](/llms.txt) for the grouped index. 2. Use [`/llms-full.txt`](/llms-full.txt) when the agent needs broad context. 3. Use [`/llms-components.txt`](/llms-components.txt) and raw component `.md` pages when authoring UI. 4. Use [`/llms-capabilities.txt`](/llms-capabilities.txt) for `std.*` and policy-gated `api.*`. 5. Use [`/llms-runtime.txt`](/llms-runtime.txt) for host and secure runtime integration. 6. Use [`/llms-toolhost.txt`](/llms-toolhost.txt) only when user input must return structured data to the host. 7. Use [`/standard/slex-standard-manifest.json`](/standard/slex-standard-manifest.json), [`/standard/slex-logic-profile.json`](/standard/slex-logic-profile.json), and [`/standard/slex-component-catalog.json`](/standard/slex-component-catalog.json) when an agent needs machine-readable authoring or validation context. SlexKit raw docs are ordinary `.md` pages with explicit `slex` fences. There is no `.mdx` route — `slex` fences are the interactive layer. ## Context Files Add SlexKit context to `AGENTS.md`, `CLAUDE.md`, or `.cursorrules`: ````md ## SlexKit This project uses SlexKit for Markdown-native interactive AI output. Documentation: https://slexkit.dev/llms-full.txt Key patterns: - Display UI uses explicit `slex` fenced blocks plus Markdown fallback. - Slex source uses `{ slex, namespace, g, layout }`; use `slex: "0.1"` for the current public protocol. - Use `std.*` for common calculations, formatting, units, and small statistics. - Use `/standard/slex-logic-profile.json` and `/standard/slex-component-catalog.json` for machine-readable rules before generating Slex. - Run `slex validate --standard` to verify the current package against bundled standard fixtures. - ToolHost is only for structured user input flows. - Untrusted or agent-generated source should use the secure runtime. - Raw docs are `.md` files with `slex` fences, not `.mdx`. ```` ## Skills The `skills/` directory provides these task entry points: - `/slexkit`: overview, architecture, and positioning - `/author`: write display-oriented `slex` fences with Markdown fallback - `/host`: integrate Markdown, Streamdown, Obsidian, or custom hosts - `/toolhost`: build confirmations, choices, and structured forms - `/secure`: configure sandbox runtime and host policy - `/update`: regenerate AI docs after API, docs, or component changes Use `/author` for display UI. Use `/toolhost` when the host must receive a submitted result. ## MCP `@slexkit/mcp` provides read-only access to SlexKit documentation, examples, standard artifacts, conformance reports, and Slex source validation. Keep the public surface small and natural: docs, examples, validate. ```slex { namespace: "ai_mcp_tools", layout: { "grid:tools": { columns: 1, mdColumns: 3, "card:docs": { title: "slexkitDocs", icon: "book-open-text", "text:body": { text: "Search or fetch Markdown docs, standard artifact JSON, or a conformance report." } }, "card:examples": { title: "slexkitExamples", icon: "code", "text:body": { text: "Browse component examples, ToolHost templates, and host integration snippets." } }, "card:validate": { title: "slexkitValidate", icon: "check-circle", "text:body": { text: "Parse Slex source and return diagnostics plus component usage." } } } } } ``` ### Quick Install ```sh npx add-mcp @slexkit/mcp ``` Or specify an app: ```sh npx add-mcp @slexkit/mcp -a claude-code npx add-mcp @slexkit/mcp -a codex npx add-mcp @slexkit/mcp -a cursor npx add-mcp @slexkit/mcp -a vscode npx add-mcp @slexkit/mcp -a zed ``` ### Manual Installation ```slex { namespace: "ai_manual_configs", layout: { "tabs:manualConfigs": { value: "cursor", tabs: [ { value: "cursor", label: "Cursor", content: { "code-block:cursor": { title: ".cursor/mcp.json", language: "json", code: "{\n \"mcpServers\": {\n \"slexkit\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@slexkit/mcp\"]\n }\n }\n}" } } }, { value: "codex", label: "Codex", content: { "code-block:codex": { title: "config.toml", language: "toml", code: "[mcp_servers.slexkit]\ncommand = \"npx\"\nargs = [\"-y\", \"@slexkit/mcp\"]" } } }, { value: "vscode", label: "VS Code", content: { "code-block:vscode": { title: ".vscode/mcp.json", language: "json", code: "{\n \"servers\": {\n \"slexkit\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@slexkit/mcp\"],\n \"type\": \"stdio\"\n }\n }\n}" } } } ] } } } ``` ## Troubleshooting - MCP server does not start: verify `npx` and MCP config JSON, then restart the IDE. - Tool calls fail: restart the MCP server and confirm `tools/list` exposes only `slexkitDocs`, `slexkitExamples`, and `slexkitValidate`. - Docs are stale: run `bun run ai:docs` or `bun run build:core`. - Wrong raw source route: use `.md` routes with `slex` fences. Do not request `.mdx`. --- # 第一个 SlexKit 卡片 URL: /zh-CN/examples/hello-slexkit Raw Markdown: /zh-CN/examples/hello-slexkit.md Source: content/examples/hello-slexkit/zh-CN.md # 第一个 SlexKit 卡片 该示例不使用 `g` 对象或交互,只用 `layout` 声明一张静态卡片。 ```slex { slex: "0.1", namespace: "learn_hello_slexkit", layout: { "section:hello": { eyebrow: "入门教程 · 1/4", title: "第一个 SlexKit 卡片", subtitle: "所有内容都是声明式的——数字、颜色、布局,全部来自 DSL。", "grid:top-stats": { columns: 1, mdColumns: 3, "stat:users": { label: "活跃用户", value: "12,847", unit: "人" }, "stat:uptime": { label: "正常运行", value: "99.97", unit: "%" }, "stat:latency": { label: "服务延迟", value: "42", unit: "ms" } }, "table:pricing": { columns: ["功能", "免费版", "专业版"], rows: [ ["可用组件", "全部", "全部"], ["自定义主题", "3 种", "无限"], ["数据导出", "JSON", "JSON / CSV / SQL"] ] }, "callout:tip": { tone: "info", text: "标题、数值、表格和颜色都来自上面的 DSL 声明,不需要额外 HTML。Markdown 承载正文,DSL 承载交互结构。" } } } } ``` 先观察结构、组件 key 和嵌套方式。下一节会在同样的结构里加入响应式数据。 --- 如果 `"12,847"` 需要动态计算,就需要把数据放进 `g` 对象,并用表达式读取。 --- # 第一个交互:滑块操控数据 URL: /zh-CN/examples/first-interaction Raw Markdown: /zh-CN/examples/first-interaction.md Source: content/examples/first-interaction/zh-CN.md # 第一个交互:滑块操控数据 从静态内容进入交互内容时,需要三样东西: 1. **`g` 对象** — 响应式状态容器 2. **`$value` / `$label` / `$tone`** — 读表达式(从 g 取值渲染) 3. **`onchange`** — 写表达式(用户操作写入 g) ```slex { slex: "0.1", namespace: "learn_first_interaction", g: { count: 42 }, layout: { "section:interact": { eyebrow: "入门教程 · 2/4", title: "第一个交互:滑块操控数据", subtitle: "滑动下面的滑块,stat 和 callout 会随 g.count 更新。", "column:controls": { "slider:count": { label: "选择数值", "$value": "g.count", min: 0, max: 100, step: 1, onchange: "g.count = Number($event)" }, "stat:countStat": { label: "当前数值", "$value": "g.count" }, "badge:level": { "$label": "g.count < 30 ? '低' : g.count < 70 ? '中' : '高'", "$tone": "g.count < 30 ? 'success' : g.count < 70 ? 'warning' : 'danger'" }, "callout:note": { "$tone": "g.count < 50 ? 'success' : 'info'", "$text": "g.count < 50 ? '当前值偏低,适合入门级负载。' : '当前值偏高,注意监控资源消耗。'" } } } } } ``` 核心公式: ``` 用户操作 → onchange → g → SlexKit 检测变化 → 所有 $value/$tone/$text 自动重算 → UI 更新 ``` 这是一条单向数据流:用户操作写入 `g`,表达式读取 `g` 并触发重渲染。不需要手动 `setState` 或 DOM 操作。 --- # 多输入协同:两个滑块联动 URL: /zh-CN/examples/multi-input-coordination Raw Markdown: /zh-CN/examples/multi-input-coordination.md Source: content/examples/multi-input-coordination/zh-CN.md # 多输入协同:两个滑块联动 多个输入变量相互影响时,可以把计算逻辑放进 `g.method()`,再用 `$if` 控制显示。 1. **`g.method()`** — 依赖其他状态的计算值(类似 Vue computed) 2. **`$if`** — 条件渲染(根据状态决定显示或隐藏组件) ```slex { slex: "0.1", namespace: "learn_multi_coordination", g: { width: 120, height: 80, area: function () { return this.width * this.height; }, isLandscape: function () { return this.width > this.height; }, ratio: function () { return (this.width / this.height).toFixed(2); } }, layout: { "section:coordinated": { eyebrow: "入门教程 · 3/4", title: "多输入协同:矩形尺寸联动", subtitle: "同时调整宽和高,面积和宽高比会自动重新计算。", "grid:params": { columns: 1, mdColumns: 2, "column:w": { "input:widthInput": { label: "宽度", "$value": "g.width", type: "number", unit: "px", onchange: "g.width = Number($event || 0)" }, "slider:widthSlider": { label: "宽度", "$value": "g.width", min: 20, max: 300, step: 5, unit: "px", onchange: "g.width = Number($event)" } }, "column:h": { "input:heightInput": { label: "高度", "$value": "g.height", type: "number", unit: "px", onchange: "g.height = Number($event || 0)" }, "slider:heightSlider": { label: "高度", "$value": "g.height", min: 20, max: 300, step: 5, unit: "px", onchange: "g.height = Number($event)" } } }, "grid:results": { columns: 1, mdColumns: 3, "stat:area": { label: "面积", "$value": "g.area()", unit: "px²" }, "stat:ratio": { label: "宽高比", "$value": "g.ratio()" }, "badge:orientation": { "$label": "g.isLandscape() ? '横向' : g.width === g.height ? '正方形' : '纵向'", "$tone": "g.isLandscape() ? 'info' : g.width === g.height ? 'success' : 'warning'" } }, "formula:areaEq": { "$tex": "'\\\\text{面积} = ' + g.width + ' \\\\times ' + g.height + ' = ' + g.area() + '\\\\text{ px}^2'" }, "callout:tip": { "$tone": "g.isLandscape() ? 'info' : 'warning'", "$text": "g.isLandscape() ? '当前为横向(Landscape)。横向更适用于宽屏展示。' : '当前为纵向(Portrait)。纵向更适用于移动端阅读。'" }, "callout:squareTip": { "$if": "g.width === g.height", tone: "success", text: "这是一个正方形!宽高完全相等。" } } } } ``` **三个新知识点:** | 概念 | 写法 | 含义 | |:---|:---|:---| | g 方法 | `area: function() { return this.width * this.height; }` | `this` 指向 g 对象本身,返回动态计算值 | | 动态公式 | `"$tex": "'...' + g.width + '...'"` | formula 组件可根据 g 值实时渲染 KaTeX | | 条件渲染 | `"$if": "g.width === g.height"` | 只有表达式返回 true 时该组件才渲染 | --- # 分支与切换:模式选择器 URL: /zh-CN/examples/tabs-and-branching Raw Markdown: /zh-CN/examples/tabs-and-branching.md Source: content/examples/tabs-and-branching/zh-CN.md # 分支与切换:模式选择器 该示例用 `select` 切换 `mode` 状态,并根据当前模式渲染不同输入和结果。 模式切换遵循 `UI = f(state)`:更新 `mode` 后,视图区域随状态切换。 ```slex { slex: "0.1", namespace: "learn_tabs_branching", g: { mode: "length", value: 100, convert: function () { if (this.mode === "length") return (this.value / 100).toFixed(2) + " m"; if (this.mode === "weight") return (this.value * 2.20462).toFixed(2) + " 磅 (lbs)"; if (this.mode === "temp") return (this.value * 9 / 5 + 32).toFixed(1) + " °F"; return "—"; }, label: function () { if (this.mode === "length") return "厘米转米"; if (this.mode === "weight") return "公斤转磅"; return "摄氏度转华氏度"; } }, layout: { "section:branching": { eyebrow: "入门教程 · 4/4", title: "分支与切换:模式选择器", subtitle: "切换下面的模式,输入的参数和计算结果会跟着变化。一种模式 = 一种 UI 状态。", "select:mode": { label: "转换模式", "$value": "g.mode", options: [ { label: "长度 (cm → m)", value: "length" }, { label: "重量 (kg → lbs)", value: "weight" }, { label: "温度 (°C → °F)", value: "temp" } ], onchange: "g.mode = String($event)" }, "input:value": { label: "输入值", "$value": "g.value", type: "number", onchange: "g.value = Number($event || 0)" }, "stat:result": { "$label": "g.label()", "$value": "g.convert()" }, "callout:guide": { "$tone": "g.mode === 'temp' ? 'warning' : 'info'", "$text": "g.mode === 'length' ? '1 米 = 100 厘米,除以 100 即可。' : g.mode === 'weight' ? '1 公斤 ≈ 2.20462 磅。' : '°F = °C × 9/5 + 32。华氏度范围更大,注意精度。'" } } } } ``` --- # 五险一金计算器 URL: /zh-CN/examples/salary-calculator Raw Markdown: /zh-CN/examples/salary-calculator.md Source: content/examples/salary-calculator/zh-CN.md # 五险一金计算器 该示例按税前工资和缴纳城市计算五险一金明细,包括个人扣除、单位缴纳和到手工资。 ```slex { slex: "0.1", namespace: "example_salary_calculator", g: { base: 20000, city: "beijing", rates: { beijing: { pensionP: 8, medicalP: 2, unemploymentP: 0.5, pensionC: 16, medicalC: 8, unemploymentC: 0.5, injury: 0.2, maternity: 0.8, housing: 12 }, shanghai: { pensionP: 8, medicalP: 2, unemploymentP: 0.5, pensionC: 16, medicalC: 8, unemploymentC: 0.5, injury: 0.2, maternity: 0.8, housing: 7 }, guangzhou: { pensionP: 8, medicalP: 2, unemploymentP: 0.5, pensionC: 16, medicalC: 8, unemploymentC: 0.5, injury: 0.2, maternity: 0.8, housing: 5 }, shenzhen: { pensionP: 8, medicalP: 2, unemploymentP: 0.5, pensionC: 16, medicalC: 8, unemploymentC: 0.5, injury: 0.2, maternity: 0.8, housing: 5 } }, currentRate: function () { return this.rates[this.city] || this.rates.beijing; }, personalRate: function () { var r = this.currentRate(); return r.pensionP + r.medicalP + r.unemploymentP + r.housing; }, companyRate: function () { var r = this.currentRate(); return r.pensionC + r.medicalC + r.unemploymentC + r.injury + r.maternity + r.housing; }, personalTotal: function () { return this.base * this.personalRate() / 100; }, companyTotal: function () { return this.base * this.companyRate() / 100; }, total: function () { return this.personalTotal() + this.companyTotal(); }, takeHome: function () { return this.base - this.personalTotal(); }, cityLabel: function () { return { beijing: "北京", shanghai: "上海", guangzhou: "广州", shenzhen: "深圳" }[this.city] || this.city; } }, layout: { "section:salary": { title: "五险一金计算器", subtitle: "输入税前工资和城市,实时计算五险一金明细。", "grid:params": { columns: 1, mdColumns: 2, "column:baseField": { "input:baseInput": { label: "税前工资", "$value": "g.base", type: "number", unit: "元/月", onchange: "g.base = Number($event || 0)" }, "slider:baseSlider": { label: "税前工资", "$value": "g.base", min: 3000, max: 50000, step: 500, unit: "元", onchange: "g.base = Number($event)" } }, "column:cityField": { "select:city": { label: "缴纳城市", "$value": "g.city", options: [ { label: "北京", value: "beijing" }, { label: "上海", value: "shanghai" }, { label: "广州", value: "guangzhou" }, { label: "深圳", value: "shenzhen" } ], onchange: "g.city = String($event)" } } }, "grid:summary": { columns: 1, mdColumns: 3, "stat:personal": { label: "个人扣除", "$value": "g.personalTotal().toFixed(0)", unit: "元" }, "stat:company": { label: "公司缴纳", "$value": "g.companyTotal().toFixed(0)", unit: "元" }, "stat:takehome": { label: "到手工资", "$value": "g.takeHome().toFixed(0)", unit: "元" } } } } } ``` 切换城市后,公积金比例变化会影响个人扣除和到手工资;示例中北京为 12%,上海为 7%。 ```slex { slex: "0.1", namespace: "example_salary_calculator", layout: { "card:detail": { title: "各项明细", "grid:personal": { columns: 1, mdColumns: 4, "stat:pension_p": { label: "养老(8%)", "$value": "(g.base * 0.08).toFixed(0)", unit: "元" }, "stat:medical_p": { label: "医疗(2%)", "$value": "(g.base * 0.02).toFixed(0)", unit: "元" }, "stat:unemployment_p": { label: "失业(0.5%)", "$value": "(g.base * 0.005).toFixed(0)", unit: "元" }, "stat:housing_p": { label: "公积金", "$value": "(g.base * g.currentRate().housing / 100).toFixed(0)", unit: "元" } }, "grid:company": { columns: 1, mdColumns: 4, "stat:pension_c": { label: "养老(16%)", "$value": "(g.base * 0.16).toFixed(0)", unit: "元" }, "stat:medical_c": { label: "医疗(8%)", "$value": "(g.base * 0.08).toFixed(0)", unit: "元" }, "stat:unemployment_c": { label: "失业(0.5%)", "$value": "(g.base * 0.005).toFixed(0)", unit: "元" }, "stat:other_c": { label: "工伤+生育", "$value": "(g.base * 0.01).toFixed(0)", unit: "元" } }, "callout:note": { "$tone": "g.personalTotal() > 3000 ? 'warning' : 'info'", "$text": "g.personalTotal() > 3000 ? '个人扣除超过3000元,到手工资可能低于预期。' : '公积金比例越高,到手工资越少,但公积金可以提取使用。'" } } } } ``` | 城市 | 养老 | 医疗 | 失业 | 公积金 | 个人合计 | |------|------|------|------|--------|----------| | 北京 | 8% | 2% | 0.5% | 12% | 22.5% | | 上海 | 8% | 2% | 0.5% | 7% | 17.5% | | 广州 | 8% | 2% | 0.5% | 5% | 15.5% | | 深圳 | 8% | 2% | 0.5% | 5% | 15.5% | --- # 软件项目成本估算器 URL: /zh-CN/examples/project-cost-estimator Raw Markdown: /zh-CN/examples/project-cost-estimator.md Source: content/examples/project-cost-estimator/zh-CN.md # 软件项目成本估算器 该示例根据团队规模、周期、人力单价和风险缓冲计算项目总成本、月均消耗和人均成本。 ```slex { slex: "0.1", namespace: "example_project_cost", g: { frontend: 2, backend: 3, tester: 1, designer: 1, months: 6, salary: 15000, teamSize: function () { return this.frontend + this.backend + this.tester + this.designer; }, laborCost: function () { return this.teamSize() * this.salary * this.months; }, equipmentCost: function () { return this.teamSize() * 5000; }, officeCost: function () { return this.teamSize() * 2000 * this.months; }, subtotal: function () { return this.laborCost() + this.equipmentCost() + this.officeCost(); }, riskBuffer: function () { return this.subtotal() * 0.15; }, totalCost: function () { return this.subtotal() + this.riskBuffer(); }, perPersonCost: function () { return this.teamSize() > 0 ? this.totalCost() / this.teamSize() : 0; }, monthlyBurn: function () { return this.months > 0 ? this.totalCost() / this.months : 0; } }, layout: { "section:estimator": { title: "软件项目成本估算器", subtitle: "输入团队配置和周期,成本自动算出来。", "card:estimator": { title: "项目成本估算", "grid:team": { columns: 1, mdColumns: 4, "column:fe": { "input:frontend": { label: "前端", "$value": "g.frontend", type: "number", unit: "人", onchange: "g.frontend = Number($event || 0)" } }, "column:be": { "input:backend": { label: "后端", "$value": "g.backend", type: "number", unit: "人", onchange: "g.backend = Number($event || 0)" } }, "column:qa": { "input:tester": { label: "测试", "$value": "g.tester", type: "number", unit: "人", onchange: "g.tester = Number($event || 0)" } }, "column:ui": { "input:designer": { label: "设计", "$value": "g.designer", type: "number", unit: "人", onchange: "g.designer = Number($event || 0)" } } }, "grid:params": { columns: 1, mdColumns: 2, "column:period": { "input:monthsInput": { label: "开发周期", "$value": "g.months", type: "number", unit: "个月", onchange: "g.months = Number($event || 0)" }, "slider:monthsSlider": { label: "开发周期", "$value": "g.months", min: 1, max: 24, step: 1, unit: "月", onchange: "g.months = Number($event)" } }, "column:salaryField": { "input:salaryInput": { label: "人均月薪", "$value": "g.salary", type: "number", unit: "元", onchange: "g.salary = Number($event || 0)" }, "slider:salarySlider": { label: "人均月薪", "$value": "g.salary", min: 8000, max: 50000, step: 1000, unit: "元", onchange: "g.salary = Number($event)" } } }, "grid:results": { columns: 1, mdColumns: 4, "stat:team": { label: "团队", "$value": "g.teamSize()", unit: "人" }, "stat:total": { label: "总成本", "$value": "g.totalCost().toFixed(0)", unit: "元" }, "stat:perperson": { label: "人均成本", "$value": "g.perPersonCost().toFixed(0)", unit: "元" }, "stat:monthly": { label: "月均消耗", "$value": "g.monthlyBurn().toFixed(0)", unit: "元" } } } } } } ``` 调整人数、周期或角色配置后,月均消耗和总成本会立即更新。 ```slex { slex: "0.1", namespace: "example_project_cost", layout: { "card:breakdown": { title: "成本构成", "grid:costs": { columns: 1, mdColumns: 3, "stat:labor": { label: "人力成本", "$value": "g.laborCost().toFixed(0)", unit: "元" }, "stat:equipment": { label: "设备成本", "$value": "g.equipmentCost().toFixed(0)", unit: "元" }, "stat:office": { label: "办公成本", "$value": "g.officeCost().toFixed(0)", unit: "元" } }, "grid:extra": { columns: 1, mdColumns: 2, "stat:risk": { label: "风险缓冲(15%)", "$value": "g.riskBuffer().toFixed(0)", unit: "元" }, "stat:total": { label: "总计", "$value": "g.totalCost().toFixed(0)", unit: "元" } }, "callout:tip": { "$tone": "g.months > 12 ? 'warning' : 'info'", "$text": "g.months > 12 ? '项目周期超过1年,建议分阶段交付以降低风险。' : '风险缓冲15%是经验值,复杂项目可调高到20-25%。'" } } } } ``` 常见配置参考: | 团队 | 周期 | 月薪 | 总成本 | |------|------|------|--------| | 3人 | 3个月 | 15k | 196,650 | | 5人 | 6个月 | 15k | 655,500 | | 8人 | 9个月 | 20k | 1,989,000 | | 10人 | 12个月 | 25k | 4,140,000 | 风险缓冲15%是经验值,复杂项目可以调到20-25%。设备和办公成本按人头估算,不含服务器和第三方服务。 --- # 分压器计算器 URL: /zh-CN/examples/voltage-divider Raw Markdown: /zh-CN/examples/voltage-divider.md Source: content/examples/voltage-divider/zh-CN.md # 分压器计算器 两个电阻串联,从中间引出电压——模拟电路中最简单的信号调理手段。做 ADC 电平转换、设定阈值电压、生成偏置电压,处处都在用。 ## 核心公式 空载分压:$V_{out} = V_{in} \times \frac{R_2}{R_1 + R_2}$ 带负载 $R_L$ 时:$V_{out,loaded} = V_{in} \times \frac{R_2 \parallel R_L}{R_1 + R_2 \parallel R_L}$ **关键经验**:分压器阻抗($R_1 \parallel R_2$)应至少 < 后级输入阻抗的 1/10。 ```slex { slex: "0.1", namespace: "example_voltage_divider", g: { vin: 5, r1: 10000, r2: 10000, rl: 100000, rParallel: function () { return this.r2 * this.rl / (this.r2 + this.rl); }, vout: function () { return this.vin * this.r2 / (this.r1 + this.r2); }, voutLoaded: function () { return this.vin * this.rParallel() / (this.r1 + this.rParallel()); }, errorPercent: function () { return Math.abs((this.voutLoaded() - this.vout()) / this.vout() * 100); }, impedanceRatio: function () { var zout = this.r1 * this.r2 / (this.r1 + this.r2); return this.rl / zout; }, loadWarning: function () { return this.impedanceRatio() < 10 ? "负载效应显著,增大 RL 或减小 R1/R2" : "分压器阻抗足够低"; } }, layout: { "section:divider": { title: "分压器计算器", subtitle: "两个电阻串联,从中间引出电压。", "card:divider": { title: "分压器计算器", "grid:params": { columns: 1, mdColumns: 2, "column:r1Field": { "input:r1Input": { label: "R1", "$value": "std.units.si(g.r1, 'Ω', 1)", type: "engineering", unit: "Ω", placeholder: "10kΩ", onchange: "if ($event.valid && $event.number > 0) g.r1 = $event.number" }, "slider:r1Slider": { label: "R1", "$value": "g.r1", min: 100, max: 1000000, step: 100, unit: "Ω", onchange: "g.r1 = Number($event)" } }, "column:r2Field": { "input:r2Input": { label: "R2", "$value": "std.units.si(g.r2, 'Ω', 1)", type: "engineering", unit: "Ω", placeholder: "10kΩ", onchange: "if ($event.valid && $event.number > 0) g.r2 = $event.number" }, "slider:r2Slider": { label: "R2", "$value": "g.r2", min: 100, max: 1000000, step: 100, unit: "Ω", onchange: "g.r2 = Number($event)" } } }, "grid:params2": { columns: 1, mdColumns: 2, "column:vinField": { "input:vinInput": { label: "输入电压 Vin", "$value": "std.units.si(g.vin, 'V', 1)", type: "engineering", unit: "V", placeholder: "5V", onchange: "if ($event.valid && $event.number > 0) g.vin = $event.number" }, "slider:vinSlider": { label: "Vin", "$value": "g.vin", min: 0.1, max: 48, step: 0.1, unit: "V", onchange: "g.vin = Number($event)" } }, "column:rlField": { "input:rlInput": { label: "负载电阻 RL", "$value": "std.units.si(g.rl, 'Ω', 1)", type: "engineering", unit: "Ω", placeholder: "100kΩ", onchange: "if ($event.valid && $event.number > 0) g.rl = $event.number" }, "slider:rlSlider": { label: "RL", "$value": "g.rl", min: 1000, max: 10000000, step: 1000, unit: "Ω", onchange: "g.rl = Number($event)" } } }, "formula:eq1": { "$tex": "'V_{out} = ' + g.vin.toFixed(1) + ' \\\\times \\\\frac{' + (g.r2/1000).toFixed(1) + '\\\\text{k}}{' + (g.r1/1000).toFixed(1) + '\\\\text{k} + ' + (g.r2/1000).toFixed(1) + '\\\\text{k}} = ' + g.vout().toFixed(3) + '\\\\text{ V}'" }, "grid:results": { columns: 1, mdColumns: 4, "stat:vout": { label: "空载 Vout", "$value": "g.vout().toFixed(3)", unit: "V" }, "stat:voutLoaded": { label: "带载 Vout", "$value": "g.voutLoaded().toFixed(3)", unit: "V" }, "stat:error": { label: "负载误差", "$value": "g.errorPercent().toFixed(2)", unit: "%" }, "badge:ratio": { "$label": "g.impedanceRatio() < 10 ? '⚠ 负载效应' : '✓ 匹配良好'", "$tone": "g.impedanceRatio() < 10 ? 'warning' : 'success'" } }, "callout:warning": { "$tone": "g.impedanceRatio() < 10 ? 'warning' : 'info'", "$text": "g.loadWarning()" } } } } } ``` ## 工程笔记 | R1 | R2 | Vout/Vin | 阻抗 | |----|----|---------|------| | 10k | 10k | 0.50 | 5k | | 10k | 3.3k | 0.25 | 2.5k | | 10k | 1k | 0.09 | 909 | | 33k | 10k | 0.23 | 7.7k | - **ADC 应用**:分压器阻抗应 < ADC 输入阻抗的 1/10,必要时加缓冲运放 - **高精度场景**:用 1% 精度电阻,R1 和 R2 用同一批次减少温漂差异 - **功率限制**:$P = V^2/R$,小阻值分压器注意发热 --- # RC 低通滤波器 URL: /zh-CN/examples/rc-low-pass-filter Raw Markdown: /zh-CN/examples/rc-low-pass-filter.md Source: content/examples/rc-low-pass-filter/zh-CN.md # RC 低通滤波器 RC 低通滤波器是模拟电路中最基础的无源滤波器——一个电阻加一个电容,就能把高频噪声从信号路径上滤掉。做 ADC 前端抗混叠、音频去嘶声、PWM 平滑输出,都会用到它。 ## 核心公式 截止频率 $f_c$(-3dB 点): $$f_c = \frac{1}{2\pi RC}$$ 对于任意频率 $f$ 的输入信号,输出幅度增益为: $$|H(f)| = \frac{1}{\sqrt{1 + (f/f_c)^2}}$$ ## 参数区 ```slex { slex: "0.1", namespace: "example_rc_low_pass_filter", g: { r: 10000, c: 100, f: 1000, cLabel: function () { return String(Math.round(this.c * 1000) / 1000); }, cutoff: function () { return 1 / (2 * Math.PI * this.r * this.c * 1e-9); }, gain: function () { return 1 / Math.sqrt(1 + Math.pow(this.f / this.cutoff(), 2)); }, gainDb: function () { return (20 * Math.log10(this.gain())).toFixed(1); }, regimeLabel: function () { return this.f < this.cutoff() * 0.1 ? "通带" : this.f > this.cutoff() * 10 ? "阻带" : "过渡带"; } }, layout: { "section:params": { title: "RC 低通滤波器", subtitle: "一个电阻加一个电容,把高频噪声滤掉。", "card:params": { title: "参数输入", "grid:inputs": { columns: 1, mdColumns: 3, "column:rField": { "input:rInput": { label: "电阻 R", "$value": "std.units.si(g.r, 'Ω', 1)", type: "engineering", unit: "Ω", placeholder: "10kΩ", onchange: "if ($event.valid && $event.number > 0) g.r = $event.number" }, "slider:rSlider": { label: "R", "$value": "g.r", min: 100, max: 100000, step: 100, unit: "Ω", onchange: "g.r = Number($event)" } }, "column:cField": { "input:cInput": { label: "电容 C", "$value": "g.cLabel() + 'nF'", type: "engineering", unit: "nF", placeholder: "100nF", onchange: "if ($event.valid && $event.number > 0) g.c = $event.unit ? $event.number * 1e9 : $event.number" }, "slider:cSlider": { label: "C", "$value": "g.c", min: 1, max: 1000, step: 1, unit: "nF", onchange: "g.c = Number($event)" } }, "column:fField": { "input:fInput": { label: "输入频率 f", "$value": "std.units.si(g.f, 'Hz', 1)", type: "engineering", unit: "Hz", placeholder: "1kHz", onchange: "if ($event.valid && $event.number >= 0) g.f = $event.number" }, "slider:fSlider": { label: "f", "$value": "g.f", min: 1, max: 100000, step: 1, unit: "Hz", onchange: "g.f = Number($event)" } } }, "stat:fc": { label: "截止频率", "$value": "g.cutoff().toFixed(1)", unit: "Hz" }, "badge:regime": { "$label": "g.regimeLabel()", "$tone": "g.f < g.cutoff() * 0.1 ? 'success' : g.f > g.cutoff() * 10 ? 'danger' : 'warning'" } } } } } ``` ## 计算结果 ```slex { slex: "0.1", namespace: "example_rc_low_pass_filter", layout: { "column:results": { "formula:fc_eq": { "$tex": "'f_c = \\\\frac{1}{2\\\\pi \\\\times ' + (g.r/1000).toFixed(1) + 'k\\\\Omega \\\\times ' + g.cLabel() + '\\\\text{nF}} = ' + g.cutoff().toFixed(1) + '\\\\text{ Hz}'" }, "row:metrics": { "stat:gain_val": { label: "幅值增益 |H(f)|", "$value": "g.gain().toFixed(4)" }, "stat:gain_db": { label: "增益", "$value": "g.gainDb()", unit: "dB", "$tone": "g.f < g.cutoff() * 0.1 ? 'success' : g.f > g.cutoff() * 10 ? 'danger' : 'warning'" } }, "callout:verdict": { "$tone": "g.f < g.cutoff() * 0.1 ? 'success' : g.f > g.cutoff() * 10 ? 'danger' : 'warning'", "$text": "g.f < g.cutoff() * 0.1 ? '信号完整通过,衰减 < 0.04 dB。' : g.f > g.cutoff() * 10 ? '信号被强烈衰减超过 20 dB,滤波器有效工作。' : '信号处于过渡带,衰减约 ' + (-20 * Math.log10(1 / Math.sqrt(1 + Math.pow(g.f / g.cutoff(), 2)))).toFixed(1) + ' dB。'" } } } } ``` ## 选型参考 下表是常见场景下的经验参数组合。把截止频率设为目标信号最高频率的 5-10 倍,可以保证通带平坦。 ```slex { slex: "0.1", namespace: "example_rc_low_pass_filter", layout: { "card:selection": { title: "选型建议", "table:guide": { columns: ["R", "C", "fc", "典型用途"], rows: [ ["1 kΩ", "100 nF", "1592 Hz", "音频低通"], ["10 kΩ", "100 nF", "159 Hz", "ADC 抗混叠"], ["100 kΩ", "10 nF", "159 Hz", "PWM 平滑"], ["1 kΩ", "1 µF", "159 Hz", "电源纹波滤波"], ["10 kΩ", "1 nF", "15915 Hz", "高频噪声抑制"] ] }, "callout:tip": { "$tone": "g.cutoff() < 100 ? 'info' : g.cutoff() > 10000 ? 'warning' : 'success'", "$text": "g.cutoff() < 100 ? '低截止频率适合电源滤波和慢信号。' : g.cutoff() > 10000 ? '高截止频率可能无法有效滤除高频噪声。' : '当前截止频率适合大多数应用场景。'" } } } } ``` ## 工程笔记 - **R 取值**:太大会增加输出阻抗和后级负载效应;太大会增大热噪声。1kΩ–100kΩ 是常用范围 - **C 取值**:nF 级 NP0/C0G 陶瓷电容温漂小、精度高;超过 100nF 考虑薄膜电容 - **负载效应**:后级输入阻抗应至少 > 10 × R,否则 $f_c$ 会偏移 - **级联**:两级 RC 串联可得到 -40dB/dec 的二阶滚降,但截止频率会降低到约 $0.37f_c$ | $f/f_c$ | 增益 | 衰减 | |:---:|:---:|:---:| | 0.1 | 0.995 | -0.04 dB | | 1.0 | 0.707 | -3 dB | | 5.0 | 0.196 | -14.2 dB | | 10.0 | 0.100 | -20 dB | --- # 波特率误差计算器 URL: /zh-CN/examples/baud-rate-calculator Raw Markdown: /zh-CN/examples/baud-rate-calculator.md Source: content/examples/baud-rate-calculator/zh-CN.md # 波特率误差计算器 嵌入式开发中,UART 波特率由系统时钟分频得到。晶振频率不能整除目标波特率时会产生误差,误差超过 ±2% 通信就可能丢帧。 ## 核心公式 $$Error = \frac{|BR_{actual} - BR_{target}|}{BR_{target}} \times 100\%$$ 实际波特率 $BR_{actual} = f_{osc} / (16 \times N)$,其中 $N = \text{round}(f_{osc} / (16 \times BR_{target}))$ 为分频寄存器整数。 ```slex { slex: "0.1", namespace: "example_baud_rate_calculator", g: { freq: 8, freqUnit: "MHz", baud: 115200, freqHz: function () { var m = { MHz: 1e6, kHz: 1e3, Hz: 1 }; return this.freq * (m[this.freqUnit] || 1e6); }, divisor: function () { return this.freqHz() / (16 * this.baud); }, regValue: function () { return Math.round(this.divisor()); }, actualBaud: function () { return this.freqHz() / (16 * this.regValue()); }, error: function () { return Math.abs((this.actualBaud() - this.baud) / this.baud * 100); }, reliability: function () { var e = this.error(); return e < 0.5 ? "优秀" : e < 2 ? "可接受" : e < 5 ? "有风险" : "不可用"; }, tone: function () { var e = this.error(); return e < 0.5 ? "success" : e < 2 ? "info" : e < 5 ? "warning" : "danger"; } }, layout: { "section:baudCalculator": { title: "波特率误差计算器", subtitle: "输入晶振频率和目标波特率,计算误差。", "card:baud": { title: "波特率误差计算器", "grid:params": { columns: 1, mdColumns: 2, "column:freqField": { "input:freq": { label: "晶振频率", "$value": "g.freq", type: "number", unit: "MHz", onchange: "g.freq = Number($event || 0)" } }, "column:baudField": { "select:baud": { label: "目标波特率", "$value": "g.baud", options: [{ label: "9600", value: 9600 }, { label: "19200", value: 19200 }, { label: "38400", value: 38400 }, { label: "57600", value: 57600 }, { label: "115200", value: 115200 }, { label: "230400", value: 230400 }, { label: "460800", value: 460800 }], onchange: "g.baud = Number($event)" } }, "column:unitField": { "select:unit": { label: "频率单位", "$value": "g.freqUnit", options: [{ label: "MHz", value: "MHz" }, { label: "kHz", value: "kHz" }, { label: "Hz", value: "Hz" }], onchange: "g.freqUnit = String($event)" } }, "column:divField": { "stat:divisor": { label: "分频比", "$value": "g.divisor().toFixed(3)" } } }, "formula:equation": { "$tex": "'\\\\text{Error} = \\\\frac{|' + g.actualBaud().toFixed(0) + ' - ' + g.baud + '|}{' + g.baud + '} \\\\times 100\\\\% = ' + g.error().toFixed(2) + '\\\\%'" }, "grid:results": { columns: 1, mdColumns: 4, "stat:actualBaud": { label: "实际波特率", "$value": "g.actualBaud().toFixed(0)", unit: "bps" }, "stat:error": { label: "误差", "$value": "g.error().toFixed(2)", unit: "%" }, "stat:reliability": { label: "可靠性", "$value": "g.reliability()", "$tone": "g.tone()" }, "stat:regValue": { label: "寄存器值", "$value": "g.regValue()" } }, "callout:advice": { "$tone": "g.tone()", "$text": "g.error() < 0.5 ? '误差极小,通信可靠。' : g.error() < 2 ? '误差在可接受范围内(<2%),绝大多数场景可用。' : g.error() < 5 ? '误差偏大,长帧通信可能失败,建议更换晶振或降低波特率。' : '误差过大,通信不可靠。请选择能整除的晶振频率。'" } } } } } ``` ## 常用晶振频率与波特率误差表 | 晶振 | 9600 | 19200 | 38400 | 57600 | 115200 | |------|------|-------|-------|-------|--------| | 1.8432 MHz | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | | 3.6864 MHz | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | | 4.0000 MHz | 8.51 | 8.51 | 8.51 | 8.51 | 8.51 | | 7.3728 MHz | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | | 8.0000 MHz | 8.51 | 8.51 | 8.51 | 8.51 | 8.51 | | 11.0592 MHz | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | | 14.7456 MHz | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | | 16.0000 MHz | 8.51 | 8.51 | 8.51 | 8.51 | 8.51 | **工程笔记**: - 零误差的关键:晶振频率能被 $16 \times BR$ 整除 - **11.0592 MHz** 是 UART 最经典的选择,对所有标准波特率零误差 - **7.3728 MHz** 和 **14.7456 MHz** 同样零误差 - 错误 < 2% 在实际工程中通常可工作,但高速长帧场景建议 < 1% --- # 搜索与过滤表格 URL: /zh-CN/examples/search-filter-table Raw Markdown: /zh-CN/examples/search-filter-table.md Source: content/examples/search-filter-table/zh-CN.md # 搜索与过滤表格 该示例用 `input` 绑定搜索关键词,用动态 `table` 生成过滤后的行,并用 `collapsible` 展开行详情。 ```slex { slex: "0.1", namespace: "example_search_filter", g: { query: "", selected: "", selectedItem: null, allItems: [ { id: "btn-1", name: "Button 按钮", category: "Action", status: "ready", notes: "支持 variant 和 size。" }, { id: "card-1", name: "Card 卡片", category: "Layout", status: "ready", notes: "最常用的分组容器。" }, { id: "input-1", name: "Input 输入框", category: "Input", status: "ready", notes: "支持 type、unit 和 placeholder。" }, { id: "tabs-1", name: "Tabs 选项卡", category: "Navigation", status: "ready", notes: "支持水平和垂直方向。" }, { id: "table-1", name: "Table 表格", category: "Display", status: "ready", notes: "columns 数组 + rows 数组。" }, { id: "formula-1", name: "Formula 公式", category: "Display", status: "ready", notes: "依赖 KaTeX 渲染 LaTeX。" }, { id: "toast-1", name: "Toast 通知", category: "Feedback", status: "preview", notes: "支持 type 变体。" }, { id: "secure-1", name: "Secure 安全运行时", category: "Tooling", status: "beta", notes: "基于 iframe 沙箱。" } ], filtered: function () { var q = this.query.toLowerCase(); if (!q) return this.allItems; return this.allItems.filter(function (item) { return item.name.toLowerCase().includes(q) || item.category.toLowerCase().includes(q); }); }, matched: function () { return this.filtered().length; }, select: function (id) { this.selected = this.selected === id ? "" : id; } }, layout: { "section:search": { eyebrow: "组件查询", title: "搜索与过滤表格", subtitle: "输入关键词实时过滤组件列表,点击任意行查看详情。", "input:query": { label: "搜索组件", "$value": "g.query", type: "text", placeholder: "输入名称或分类关键词...", onchange: "g.query = String($event || '')" }, "stat:matched": { "$label": "'匹配结果'", "$value": "g.matched()", "$unit": "'/' + g.allItems.length + ' 项'" }, "table:list": { columns: ["名称", "分类", "状态", ""], "$rows": "g.filtered().map(function(item) { return [item.name, item.category, item.status, item.id]; })" }, "callout:empty": { "$if": "g.matched() === 0", tone: "warning", "$text": "'未找到匹配「' + g.query + '」的组件。'" } } } } ``` **核心技巧:** - `input` 的 `onchange` 更新 `g.query` → 触发 `g.filtered()` 重新计算 - `g.filtered()` 用 `filter` 过滤 `allItems` 数组 - `"$rows"` 动态计算行的二维数组——每个 item 映射为一行 - `g.matched()` 返回过滤后数量,用于 stat 和 callout 的条件显示 - `$if` 在无匹配时显示空结果提示 这是 `input` 驱动动态表格的基本模式。相比硬编码 rows,动态 rows 可以随输入实时变化。 --- ## 进阶玩法:展开行详情 ```slex { slex: "0.1", namespace: "example_search_filter", layout: { "section:detail": { eyebrow: "组件详情", title: "选中查看详情", "accordion:faq": { multiple: true, items: [ { value: "btn-1", label: "Button 按钮", icon: "cursor-click", content: "触发操作的基础组件。支持 variant (solid/outline/ghost) 和 size (sm/md/lg) 等变体。" }, { value: "card-1", label: "Card 卡片", icon: "rectangle", content: "内容分组容器。最常用的布局组件之一,比 section 更轻量。" }, { value: "input-1", label: "Input 输入框", icon: "textbox", content: "单行或数字输入。支持 type、unit、placeholder 等属性。" } ] } } } } ``` ## 为什么动态 rows 值得学? 静态表格的 `rows` 是硬编码二维数组。数据量增加或需要条件筛选时,可以用 `"$rows"` 在 `g` 方法中动态生成行数据: - **文档内数据浏览**:目录、API 列表、配置项 - **AI 输出展示**:大模型生成的表格结果需要可筛选 - **知识库查询**:搜索内部组件/API/术语 --- --- # 项目仪表盘 URL: /zh-CN/examples/project-dashboard Raw Markdown: /zh-CN/examples/project-dashboard.md Source: content/examples/project-dashboard/zh-CN.md # 项目仪表盘 该示例用 `section` 做区块分组,`grid` 做多列布局,并用多张 card 展示 Sprint 进度、质量指标和团队健康度。 ```slex { slex: "0.1", namespace: "example_dashboard", g: { sprint: 8, team: 6, sprintProgress: 72, bugs: 12, resolved: 9, scope: "on-track", bugRate: function () { return this.resolved / this.bugs * 100; }, teamLoad: function () { return Math.min(100, this.sprint / this.team * 20); }, scopeStatus: function () { return this.scope === "on-track" ? "正常" : this.scope === "at-risk" ? "有风险" : "已偏离"; } }, layout: { "section:dashboard": { eyebrow: "Sprint 概览", title: "项目仪表盘 · Sprint 24", subtitle: "数据截止今日 10:00 AM。拖滑动条查看不同假想数据的效果。", "grid:row1": { columns: 1, mdColumns: 3, "card:sprint": { title: "Sprint 进度", "progress:sp": { label: "完成度", "$value": "g.sprintProgress" }, "stat:scope": { label: "范围状态", "$value": "g.scopeStatus()" }, "badge:flag": { "$label": "g.scope === 'on-track' ? '正常' : g.scope === 'at-risk' ? '⚠ 预警' : '🚨 偏离'", "$tone": "g.scope === 'on-track' ? 'success' : g.scope === 'at-risk' ? 'warning' : 'danger'" } }, "card:quality": { title: "质量指标", "stat:bugs": { label: "剩余缺陷", value: "3", unit: "个" }, "progress:bugFix": { label: "修复率", "$value": "g.bugRate()" }, "badge:trend": { label: "趋势:改善中", tone: "success" } }, "card:team": { title: "团队健康度", "stat:members": { label: "团队成员", value: "6", unit: "人" }, "progress:load": { label: "负载指数", "$value": "g.teamLoad()" }, "callout:note": { "$tone": "g.teamLoad() > 80 ? 'warning' : 'info'", "$text": "g.teamLoad() > 80 ? '负载偏高,建议调整任务分配。' : '团队负载在健康范围内。'" } } }, "card:detail": { title: "详细数据", "table:tasks": { columns: ["任务", "负责人", "状态", "耗时"], rows: [["API 重构", "张三", "已完成", "3d"], ["前端组件", "李四", "进行中", "2d"], ["集成测试", "王五", "代码审查", "1.5d"], ["性能优化", "赵六", "待开始", "—"]] }, "callout:help": { "$tone": "g.bugRate() < 80 ? 'warning' : 'success'", "$text": "g.bugRate() < 80 ? '缺陷修复率低于80%,建议优先处理高优先级缺陷。' : '缺陷修复率良好,项目质量可控。'" } } } } } ``` **仪表盘的设计思路:** - 用 `section` 做顶层分组(带 eyebrow 和 subtitle,语义清晰) - 用 `grid` 做多列布局,每个格子放一个 `card` - 每个 card 内放不同关注维度的 stat / progress / badge - 底部放一个详情 card,展示表格数据(任务列表) - 通过 `$text` 和 `$tone` 在 callout 中做条件提示 类似结构可用于技术 Leader 周报面板、发布质检看板、团队 OKR 追踪和 SRE 服务大盘。 --- # ToolHost 表单提问 URL: /zh-CN/examples/form-wizard-steps Raw Markdown: /zh-CN/examples/form-wizard-steps.md Source: content/examples/form-wizard-steps/zh-CN.md # ToolHost 表单提问 当对话需要补齐项目信息、服务配置或工单字段时,ToolHost 可以渲染表单卡片。用户提交后,结果以结构化数据返回。 ```slex { slex: "0.1", namespace: "example_form_wizard", g: { submitted: false, formData: null, fields: { name: "", description: "", type: "web", priority: "medium" }, submit: function () { this.submitted = true; this.formData = { name: this.fields.name, description: this.fields.description, type: this.fields.type, priority: this.fields.priority, timestamp: new Date().toLocaleString() }; } }, layout: { "section:toolhost": { eyebrow: "ToolHost · 表单提问", title: "收集项目信息", subtitle: "表单提交后,ToolHost 返回结构化结果。", "callout:context": { tone: "info", text: "需要创建一个新项目,请填写以下信息。" }, "grid:fields": { columns: 1, mdColumns: 2, "input:name": { label: "项目名称", "$value": "g.fields.name", placeholder: "my-project", onchange: "g.fields.name = String($event || '')" }, "input:description": { label: "项目描述", "$value": "g.fields.description", placeholder: "简短描述项目用途", onchange: "g.fields.description = String($event || '')" }, "select:type": { label: "项目类型", "$value": "g.fields.type", options: [ { label: "Web 应用", value: "web" }, { label: "API 服务", value: "api" }, { label: "CLI 工具", value: "cli" } ], onchange: "g.fields.type = String($event)" }, "select:priority": { label: "优先级", "$value": "g.fields.priority", options: [ { label: "低", value: "low" }, { label: "中", value: "medium" }, { label: "高", value: "high" } ], onchange: "g.fields.priority = String($event)" } }, "grid:actions": { columns: 2, "button:submit": { label: "提交", onclick: "g.submit()" }, "button:skip": { label: "跳过" } }, "callout:result": { "$tone": "g.submitted ? 'success' : 'info'", "$text": "g.submitted ? '已提交:' + g.formData.name + '(' + g.formData.type + ')' : '等待用户填写...'" }, "code-block:toolresult": { title: "返回给宿主的 ToolResult", language: "json", "$code": "g.submitted ? JSON.stringify({ toolCallId: 'call_abc123', toolName: 'create-project', status: 'submitted', value: g.formData }, null, 2) : '// 提交后显示 ToolResult'" } } } } ``` --- --- # ToolHost 工具调用 UI URL: /zh-CN/examples/toolhost-demo Raw Markdown: /zh-CN/examples/toolhost-demo.md Source: content/examples/toolhost-demo/zh-CN.md # ToolHost 工具调用 UI 当 Agent 发起 `function_call` 时,浏览器宿主可以把它渲染成对话里的 ToolHost 工具卡片;用户提交后,宿主按原 `call_id` 写回 `function_call_output`,并把结果记录留在轨迹里。本页只用发布窗口、负责人和回滚条件作为工具参数示例,不连接模型或后端。 --- # 技术选型评估 URL: /zh-CN/examples/tech-selection-evaluator Raw Markdown: /zh-CN/examples/tech-selection-evaluator.md Source: content/examples/tech-selection-evaluator/zh-CN.md # 技术选型评估 该示例把前端框架选型拆成四个可调维度:性能、生态、学习曲线和维护成本。选择技术栈后,下方评分和结论会自动更新。 ```slex { slex: "0.1", namespace: "example_tech_selection", g: { tech: "react", performance: 85, ecosystem: 95, learning: 70, maintenance: 80, techLabel: function () { return { react: "React", vue: "Vue", svelte: "Svelte", angular: "Angular" }[this.tech] || this.tech; }, totalScore: function () { return (this.performance * 0.3 + this.ecosystem * 0.25 + this.learning * 0.2 + this.maintenance * 0.25).toFixed(1); }, recommendation: function () { var s = parseFloat(this.totalScore()); return s >= 85 ? "强烈推荐" : s >= 75 ? "推荐" : s >= 60 ? "可以考虑" : "不推荐"; }, riskLevel: function () { var s = parseFloat(this.totalScore()); return s >= 85 ? "低" : s >= 75 ? "中" : "高"; }, scores: function () { var data = { react: { performance: 85, ecosystem: 95, learning: 70, maintenance: 80 }, vue: { performance: 80, ecosystem: 85, learning: 85, maintenance: 85 }, svelte: { performance: 95, ecosystem: 70, learning: 90, maintenance: 90 }, angular: { performance: 80, ecosystem: 80, learning: 60, maintenance: 75 } }; return data[this.tech] || data.react; } }, layout: { "section:select": { eyebrow: "决策辅助", title: "技术选型评估", subtitle: "选一个技术栈,下面的评分和结论自动跟着变。", "card:select": { title: "选择技术栈", "select:tech": { label: "技术栈", "$value": "g.tech", options: [ { label: "React", value: "react" }, { label: "Vue", value: "vue" }, { label: "Svelte", value: "svelte" }, { label: "Angular", value: "angular" } ], onchange: "g.tech = String($event); var s = g.scores(); g.performance = s.performance; g.ecosystem = s.ecosystem; g.learning = s.learning; g.maintenance = s.maintenance;" }, "badge:current": { "$label": "'当前:' + g.techLabel()", tone: "info" } } } } } ``` 拖动滑块后,推荐结果和风险等级会实时更新;三个独立代码块通过同一份状态联动。 ```slex { slex: "0.1", namespace: "example_tech_selection", layout: { "card:scoring": { title: "评分调整", "grid:sliders": { columns: 1, mdColumns: 2, "column:left": { "slider:performance": { label: "性能(30%)", "$value": "g.performance", min: 0, max: 100, step: 5, onchange: "g.performance = Number($event)" }, "slider:ecosystem": { label: "生态系统(25%)", "$value": "g.ecosystem", min: 0, max: 100, step: 5, onchange: "g.ecosystem = Number($event)" } }, "column:right": { "slider:learning": { label: "学习曲线(20%)", "$value": "g.learning", min: 0, max: 100, step: 5, onchange: "g.learning = Number($event)" }, "slider:maintenance": { label: "维护成本(25%)", "$value": "g.maintenance", min: 0, max: 100, step: 5, onchange: "g.maintenance = Number($event)" } } }, "grid:weights": { columns: 1, mdColumns: 4, "stat:perf": { label: "性能(30%)", "$value": "g.performance", unit: "分" }, "stat:eco": { label: "生态(25%)", "$value": "g.ecosystem", unit: "分" }, "stat:learn": { label: "学习(20%)", "$value": "g.learning", unit: "分" }, "stat:maint": { label: "维护(25%)", "$value": "g.maintenance", unit: "分" } } } } } ``` ```slex { slex: "0.1", namespace: "example_tech_selection", layout: { "card:result": { title: "综合评估", "grid:scores": { columns: 1, mdColumns: 3, "stat:total": { label: "综合评分", "$value": "g.totalScore()" }, "stat:recommendation": { label: "推荐程度", "$value": "g.recommendation()", "$tone": "parseFloat(g.totalScore()) >= 85 ? 'success' : parseFloat(g.totalScore()) >= 75 ? 'info' : 'warning'" }, "stat:risk": { label: "风险等级", "$value": "g.riskLevel()", "$tone": "parseFloat(g.totalScore()) >= 85 ? 'success' : parseFloat(g.totalScore()) >= 75 ? 'warning' : 'danger'" } }, "callout:advice": { "$tone": "parseFloat(g.totalScore()) >= 85 ? 'success' : parseFloat(g.totalScore()) >= 75 ? 'info' : 'warning'", "$text": "parseFloat(g.totalScore()) >= 85 ? g.techLabel() + ' 综合优秀,强烈推荐。' : parseFloat(g.totalScore()) >= 75 ? g.techLabel() + ' 综合良好,推荐采用。' : g.techLabel() + ' 综合一般,建议谨慎。'" } } } } ``` 默认评分参考: | 技术栈 | 性能 | 生态 | 学习 | 维护 | 综合 | |--------|------|------|------|------|------| | React | 85 | 95 | 70 | 80 | 82.5 | | Vue | 80 | 85 | 85 | 85 | 83.75 | | Svelte | 95 | 70 | 90 | 90 | 85.5 | | Angular | 80 | 80 | 60 | 75 | 73.75 | 权重分配:性能30%、生态25%、学习曲线20%、维护成本25%。可以按团队实际情况调整。 --- # 自建还是外购决策 URL: /zh-CN/examples/roi-estimator Raw Markdown: /zh-CN/examples/roi-estimator.md Source: content/examples/roi-estimator/zh-CN.md # 自建还是外购决策 该示例把自建/外购决策拆成四个维度:功能覆盖、成本、时间线和风险。调整评分后,结论会自动更新。 ```slex { slex: "0.1", namespace: "example_build_vs_buy", g: { scope: "core", buildFit: 60, buildTime: 6, buildCost: 80, buyFit: 85, buyTime: 1, buyCost: 40, buyVendorLock: 30, buildTotal: function () { return (this.buildFit + (100 - this.buildCost) + (100 - this.buildTime * 10)) / 3; }, buyTotal: function () { return (this.buyFit + (100 - this.buyCost) + (100 - this.buyTime * 10) - this.buyVendorLock * 0.5) / 3; }, recommendation: function () { if (this.scope === "core") return this.buildTotal() >= this.buyTotal() ? "自建" : "外购(但建议评估长期成本)"; return this.buyTotal() >= this.buildTotal() ? "外购" : "自建(非核心功能自建需谨慎)"; }, diff: function () { return Math.abs(this.buildTotal() - this.buyTotal()); } }, layout: { "section:decision": { eyebrow: "技术决策", title: "自建还是外购决策", subtitle: "对比两个方案的各维度评分,系统综合推荐。拖滑块调整评分看结论变化。", "select:scope": { label: "功能定位", "$value": "g.scope", options: [ { label: "核心业务(差异化的关键)", value: "core" }, { label: "辅助功能(非核心)", value: "non-core" } ], onchange: "g.scope = String($event)" }, "table:comparison": { columns: ["维度", "自建方案", "外购方案"], rows: [ ["功能匹配度", "g.buildFit + '%'", "g.buyFit + '%'"], ["上线时间", "g.buildTime + ' 个月'", "g.buyTime + ' 个月'"], ["成本评分", "g.buildCost + '/100'", "g.buyCost + '/100'"], ["供应商锁定", "—", "g.buyVendorLock + '/100'"] ] }, "grid:sliders": { columns: 1, mdColumns: 2, "column:build": { "card:buildSliders": { title: "自建方案", "slider:buildFit": { label: "功能匹配度", "$value": "g.buildFit", min: 0, max: 100, step: 5, onchange: "g.buildFit = Number($event)" }, "slider:buildTime": { label: "上线时间(月)", "$value": "g.buildTime", min: 1, max: 24, step: 1, unit: "月", onchange: "g.buildTime = Number($event)" }, "slider:buildCost": { label: "成本评分", "$value": "g.buildCost", min: 0, max: 100, step: 5, onchange: "g.buildCost = Number($event)" } } }, "column:buy": { "card:buySliders": { title: "外购方案", "slider:buyFit": { label: "功能匹配度", "$value": "g.buyFit", min: 0, max: 100, step: 5, onchange: "g.buyFit = Number($event)" }, "slider:buyTime": { label: "上线时间(月)", "$value": "g.buyTime", min: 1, max: 24, step: 1, unit: "月", onchange: "g.buyTime = Number($event)" }, "slider:buyCost": { label: "成本评分", "$value": "g.buyCost", min: 0, max: 100, step: 5, onchange: "g.buyCost = Number($event)" }, "slider:lock": { label: "供应商锁定风险", "$value": "g.buyVendorLock", min: 0, max: 100, step: 5, onchange: "g.buyVendorLock = Number($event)" } } } }, "grid:results": { columns: 1, mdColumns: 3, "stat:buildScore": { label: "自建综合得分", "$value": "g.buildTotal().toFixed(1)" }, "stat:buyScore": { label: "外购综合得分", "$value": "g.buyTotal().toFixed(1)" }, "badge:winner": { "$label": "g.recommendation().startsWith('自建') ? '建议自建' : '建议外购'", "$tone": "g.diff() < 10 ? 'warning' : g.recommendation().startsWith('自建') ? 'info' : 'success'" } }, "callout:advice": { "$tone": "g.diff() < 10 ? 'warning' : 'info'", "$text": "g.diff() < 10 ? '两个方案得分非常接近——建议引入更多决策者参与讨论,或做小范围 POC。' : g.recommendation() + ' 方案的得分明显更高。但请结合团队实际能力和战略方向做最终决定。'" }, "accordion:detail": { multiple: true, items: [ { value: "cost", label: "成本说明", content: "成本评分越低越好(0 = 零成本,100 = 极高成本)。外购方案需额外考虑供应商锁定风险。" }, { value: "scope", label: "核心 vs 非核心策略", content: "核心业务功能通常倾向自建以保持控制力和差异化。非核心功能外购可以释放团队精力。" }, { value: "hybrid", label: "第三条路:混合方案", content: "也可以考虑先外购快速上线,同时内部规划自建替代方案,等自建成熟后迁移。" } ] } } } } ``` **Build vs Buy 决策模型的要点:** - `select` 定义功能定位(核心/非核心),影响决策偏向 - 两套 slider 独立调整各自评分 - `buildTotal()` 和 `buyTotal()` 用加权公式计算综合得分 - `recommendation()` 结合功能定位和得分给出建议 - accordion 提供额外的决策指南(成本说明、策略建议、混合方案) 这个框架把主观判断拆成可比较的评分项。 --- # 跨文档状态实验室 URL: /zh-CN/examples/cross-doc-state-lab Raw Markdown: /zh-CN/examples/cross-doc-state-lab.md Source: content/examples/cross-doc-state-lab/zh-CN.md # 跨文档状态实验室 同一篇 Markdown 中的多个 `slex` 代码块可以通过相同 `namespace` 共享 `g` 状态。 下面是三个独立的 ` ```slex ` fence——一个控制面板和两个观察面板。试试修改控制面板的值,看下方两个面板实时响应。 ## 主控面板 ```slex { slex: "0.1", namespace: "example_cross_doc_lab", g: { color: "blue", size: 16, theme: "light", style: function () { return 'color: ' + this.color + '; font-size: ' + this.size + 'px;'; } }, layout: { "section:control": { eyebrow: "平台能力", title: "跨文档状态实验室 · 主控面板", subtitle: "修改以下任何参数——下方两个独立 fence 块的卡片会同步更新。", "grid:controls": { columns: 1, mdColumns: 3, "select:color": { label: "文字颜色", "$value": "g.color", options: [ { label: "蓝色", value: "blue" }, { label: "绿色", value: "green" }, { label: "橙色", value: "orange" }, { label: "紫色", value: "purple" } ], onchange: "g.color = String($event)" }, "slider:size": { label: "字体大小", "$value": "g.size", min: 8, max: 48, step: 2, unit: "px", onchange: "g.size = Number($event)" }, "select:theme": { label: "卡片主题", "$value": "g.theme", options: [ { label: "明亮", value: "light" }, { label: "暗色", value: "dark" }, { label: "信息", value: "info" } ], onchange: "g.theme = String($event)" } }, "badge:note": { "$label": "'样式 ' + g.color + ' ' + g.size + 'px'", tone: "info" } } } } ``` ## 观察面板 A(同一 namespace,不同 fence 块) ```slex { slex: "0.1", namespace: "example_cross_doc_lab", layout: { "card:a": { title: "观察面板 A — 纯文本样式", "column:stylePreview": { "text:styleMeta": { "$text": "'字体大小:' + g.size + 'px'" }, "text:styledValue": { "$text": "g.color", "$color": "g.color", "$size": "g.size" } }, "callout:preview": { "$tone": "g.theme === 'dark' ? 'danger' : g.theme === 'info' ? 'info' : 'success'", "$text": "g.theme === 'dark' ? '暗色模式:适合夜间阅读的配色方案。' : g.theme === 'info' ? '信息模式:用于强调技术细节。' : '明亮模式:默认的文档阅读配色。'" } } } } ``` ## 观察面板 B ```slex { slex: "0.1", namespace: "example_cross_doc_lab", layout: { "card:b": { title: "观察面板 B — 参数详情", "grid:params": { columns: 1, mdColumns: 3, "stat:col": { label: "颜色", "$value": "g.color" }, "stat:sz": { label: "字号", "$value": "g.size", unit: "px" }, "stat:th": { label: "主题", "$value": "g.theme" } }, "badge:sync": { "$label": "'已同步 ' + g.color", "$tone": "g.color === 'blue' ? 'info' : g.color === 'green' ? 'success' : g.color === 'orange' ? 'warning' : 'info'" } } } } ``` **三个 fence 块**,同一个 `namespace: "example_cross_doc_lab"`,所有组件共享 `g` 对象。主控面板中的颜色和大小变化会同步到两个观察面板。 --- ### 这意味着什么? 在一篇长篇 Markdown 文档中: ``` [控制面板 — 选择行业/指标/时间范围] ... 30 段 Markdown 叙事 ... [图表 A — 自动反映控制面板的选项] ... 更多分析文字 ... [图表 B — 同一份状态的不同可视化] ``` 每个 ` ```slex ` 块可以独立渲染;namespace 相同时,它们共享状态。常见用法包括: - **技术白皮书**:顶部选参数,中间分析,底部结论,全程联动 - **项目协作文档**:状态跟踪表格在顶部,各团队任务卡片散布在正文中 - **AI 输出增强**:模型生成的多个可视化节点共享同一份推理结果 这些场景都依赖同一个机制:多块 fence 共享同一份状态,而不是把每块 UI 当成完全独立的组件。 --- # JSONPlaceholder 网络请求实验台 URL: /zh-CN/examples/network-policy-fetch-card Raw Markdown: /zh-CN/examples/network-policy-fetch-card.md Source: content/examples/network-policy-fetch-card/zh-CN.md # JSONPlaceholder 网络请求实验台 该示例让用户在 secure runtime 沙盒内选择网络任务:读取 posts、查看详情、拉取评论、按用户过滤,或向 JSONPlaceholder 发起演示 POST。请求不会从 iframe 直接出网,而是通过 `api.fetch()` 交给宿主,由宿主按 allowlist、方法、超时、请求体大小和响应类型决定是否代理。 ```slex { slex: "0.1", namespace: "example_jsonplaceholder_network_lab", g: { scenario: "posts", postId: 1, userId: 1, timeout: 3000, title: "SlexKit network demo", status: "未请求", statusCode: "-", elapsed: "-", response: "选择一个网络任务,然后点击“发起请求”。", lastUrl: "https://jsonplaceholder.typicode.com/posts", method: function () { return this.scenario === "create" ? "POST" : "GET"; }, url: function () { if (this.scenario === "detail") return "https://jsonplaceholder.typicode.com/posts/" + this.postId; if (this.scenario === "comments") return "https://jsonplaceholder.typicode.com/posts/" + this.postId + "/comments"; if (this.scenario === "user-posts") return "https://jsonplaceholder.typicode.com/users/" + this.userId + "/posts"; if (this.scenario === "create") return "https://jsonplaceholder.typicode.com/posts"; return "https://jsonplaceholder.typicode.com/posts?_limit=5"; }, requestBody: function () { if (this.scenario !== "create") return undefined; return { title: this.title, body: "这是一条从 SlexKit secure runtime 发起、由宿主代理的演示请求。", userId: this.userId }; }, description: function () { if (this.scenario === "detail") return "读取单篇 post,适合详情页或引用卡片。"; if (this.scenario === "comments") return "读取某篇 post 的评论,适合评论摘要、审阅流和证据面板。"; if (this.scenario === "user-posts") return "按用户读取 posts,适合个人空间、作者档案或关联资源列表。"; if (this.scenario === "create") return "提交一条演示 post。JSONPlaceholder 会返回假写入结果,不会持久化。"; return "读取最新 posts 列表,适合 feed、任务列表和知识库索引。"; }, riskText: function () { if (this.method() === "POST") return "POST 已被限制为 JSONPlaceholder origin,且请求体大小受 policy 约束。"; return "GET 请求仍然要经过 origin、超时、响应大小和 content-type 校验。"; }, requestSnippet: function () { var body = this.requestBody(); var lines = [ "await api.fetch('" + this.url() + "', {", " method: '" + this.method() + "',", " timeoutMs: " + this.timeout + "," ]; if (body) lines.push(" body: " + JSON.stringify(body, null, 2).replace(/\n/g, "\n ") + ","); lines.push(" credentials: 'omit'"); lines.push("})"); return lines.join("\n"); }, policyRows: function () { return [ { item: "Origin", value: "https://jsonplaceholder.typicode.com", reason: "只允许演示 API" }, { item: "Method", value: "GET, POST", reason: "读列表/详情和创建演示数据" }, { item: "Credentials", value: "omit", reason: "不携带 cookie 或站点身份" }, { item: "Content-Type", value: "application/json", reason: "拒绝非 JSON 响应进入沙盒" }, { item: "Body", value: "<= 4096 bytes", reason: "避免大请求体被模型输出滥用" } ]; }, async run(api) { var targetUrl = String(this.url()); this.status = "请求中"; this.statusCode = "-"; this.elapsed = "-"; this.lastUrl = targetUrl; this.response = "等待宿主代理 " + this.method() + " " + targetUrl; try { var result = await api.fetch(targetUrl, { method: this.method(), timeoutMs: this.timeout, body: this.requestBody(), credentials: "omit" }); this.status = result.ok ? "成功" : "HTTP 错误"; this.statusCode = String(result.status) + " " + result.statusText; this.elapsed = Math.round(result.elapsedMs) + " ms"; this.response = JSON.stringify(result.data === undefined ? result.text : result.data, null, 2).slice(0, 2400); } catch (error) { this.status = api.isPolicyError(error) ? "Policy 拦截" : api.isTimeoutError(error) ? "超时" : "网络失败"; this.statusCode = api.isPolicyError(error) ? "policy" : api.isTimeoutError(error) ? "timeout" : "network"; var elapsedMs = error && typeof error === "object" && typeof error.elapsedMs === "number" ? error.elapsedMs : undefined; this.elapsed = elapsedMs === undefined ? "-" : Math.round(elapsedMs) + " ms"; this.response = targetUrl + "\n" + api.errorMessage(error); } }, async runBlocked(api) { var targetUrl = "https://example.com/posts/1"; this.status = "请求中"; this.statusCode = "-"; this.elapsed = "-"; this.lastUrl = targetUrl; this.response = "这次请求故意访问 allowlist 外的 origin,应该被 host policy 拦截。"; try { await api.get(targetUrl, { timeoutMs: this.timeout, credentials: "omit" }); this.status = "异常通过"; this.statusCode = "unexpected"; this.response = "如果看到这行,说明 policy 没有按预期拦截。"; } catch (error) { this.status = api.isPolicyError(error) ? "Policy 拦截" : "失败"; this.statusCode = api.isPolicyError(error) ? "origin_blocked" : "network"; this.response = targetUrl + "\n" + api.errorMessage(error); } } }, layout: { "section:network": { eyebrow: "平台能力", title: "JSONPlaceholder 网络请求实验台", subtitle: "在沙盒内选择网络任务,请求通过 host policy 代理。", "card:network": { title: "JSONPlaceholder 请求实验台", "callout:intent": { tone: "info", "$text": "g.description()" }, "grid:controls": { columns: 1, mdColumns: 2, "select:scenario": { label: "网络任务", "$value": "g.scenario", options: [ { label: "Posts 列表 GET /posts", value: "posts" }, { label: "Post 详情 GET /posts/:id", value: "detail" }, { label: "评论列表 GET /posts/:id/comments", value: "comments" }, { label: "用户 posts GET /users/:id/posts", value: "user-posts" }, { label: "创建 post POST /posts", value: "create" } ], onchange: "g.scenario = String($event)" }, "slider:postId": { label: "Post ID", "$value": "g.postId", min: 1, max: 10, step: 1, onchange: "g.postId = Number($event)" }, "slider:userId": { label: "User ID", "$value": "g.userId", min: 1, max: 10, step: 1, onchange: "g.userId = Number($event)" }, "slider:timeout": { label: "超时上限", "$value": "g.timeout", min: 500, max: 8000, step: 500, unit: "ms", onchange: "g.timeout = Number($event)" } }, "row:actions": { "button:run": { label: "发起请求", icon: "paper-plane-tilt", onclick: "g.run(api)" }, "button:block": { label: "测试拦截", variant: "secondary", icon: "shield-warning", onclick: "g.runBlocked(api)" } }, "grid:status": { columns: 1, mdColumns: 3, "stat:method": { label: "方法", "$value": "g.method()" }, "stat:status": { label: "状态", "$value": "g.status" }, "stat:elapsed": { label: "耗时", "$value": "g.elapsed" } }, "code-block:request": { title: "沙盒内请求代码", language: "ts", "$code": "g.requestSnippet()" }, "code-block:response": { title: "宿主代理响应", language: "json", "$code": "g.response" }, "table:policy_matrix": { columns: [ { key: "item", label: "Policy 项" }, { key: "value", label: "允许值" }, { key: "reason", label: "原因" } ], "$rows": "g.policyRows()" }, "callout:policy_note": { "$tone": "g.status === 'Policy 拦截' ? 'warning' : 'success'", "$text": "g.riskText()" } } } } } ``` --- # assistant-ui 接入 URL: /zh-CN/examples/assistant-ui-host Raw Markdown: /zh-CN/examples/assistant-ui-host.md Source: content/examples/assistant-ui-host/zh-CN.md # assistant-ui 接入 assistant-ui 项目已经用 `@assistant-ui/react-streamdown` 渲染文本消息时,可以用 `@slexkit/assistant-ui` 替换 text part 里的 `slex` language block。thread、composer、message parts、runtime 和 tool UI 仍由 assistant-ui 处理。 下面的可运行演示是一个静态 assistant-ui transcript,用于验证 adapter 在 assistant-ui message-part 上下文中的渲染行为;它不连接模型、API key 或 ToolHost 流程。 ```sh bun run --filter @slexkit/assistant-ui build bun examples/dev-server.mjs assistant-ui ``` 源码位于 [`examples/assistant-ui`](https://github.com/slexkit/slexkit/tree/main/examples/assistant-ui)。页面用 `useExternalStoreRuntime` 和 `AssistantRuntimeProvider` 构造 thread,再通过 `SlexKitAssistantStreamdownText` 渲染 text parts。 [打开集成指南](/zh-CN/docs/guides/integration) · [查看可运行源码](https://github.com/slexkit/slexkit/tree/main/examples/assistant-ui) 安装: ```sh npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown @slexkit/assistant-ui @assistant-ui/react @assistant-ui/react-streamdown streamdown react react-dom ``` 导入样式: ```ts import "@slexkit/theme-shadcn/style.css"; import "@slexkit/assistant-ui/style.css"; ``` 接到 assistant message: ```tsx import { MessagePrimitive } from "@assistant-ui/react"; import { SlexKitAssistantStreamdownText } from "@slexkit/assistant-ui"; export function AssistantMessage() { return ( {({ part }) => part.type === "text" ? ( ) : null } ); } ``` 模型输出示例: ````md ```slex { namespace: "assistant_status", g: {}, layout: { "text:status": { text: "Rendered inside assistant-ui." } } } ``` ```` ## 处理范围 | 项目 | 约定 | | --- | --- | | Fence language | `slex` | | Runtime | 默认 `secure` | | Markdown host | `@assistant-ui/react-streamdown` | | ToolHost | 不处理 | ToolHost/tool-call 渲染需要单独接入。这个 adapter 只处理 assistant-ui text message parts 里的 Markdown fence runtime。 项目已有 `StreamdownTextPrimitive` 包装时,可以用 `createSlexKitAssistantStreamdownComponents()` 只合并 `slex` language override。 --- # Streamdown 接入 URL: /zh-CN/examples/streamdown-host Raw Markdown: /zh-CN/examples/streamdown-host.md Source: content/examples/streamdown-host/zh-CN.md # Streamdown 接入 如果 React 页面已经使用 Streamdown 渲染 Markdown,可以用 `@slexkit/streamdown` 接入 SlexKit。该示例复用官网的 RC 低通滤波器内容,演示 SlexKit 组件在 Streamdown 页面中的渲染方式。 本地运行: ```sh bun run build:core bun run --filter @slexkit/streamdown build bun examples/dev-server.mjs streamdown ``` 源码位于 [`examples/streamdown`](https://github.com/slexkit/slexkit/tree/main/examples/streamdown)。Streamdown 与 Tiptap 示例使用同一份 RC 低通滤波器内容,便于对照两种宿主的接入方式。 [打开集成指南](/zh-CN/docs/guides/integration) · [查看可运行源码](https://github.com/slexkit/slexkit/tree/main/examples/streamdown) ## 接入方式 | 项目 | 约定 | | --- | --- | | Fence language | `slex` | | Runtime | `trusted` 或 `secure` | | Markdown 宿主 | Streamdown | 普通 Markdown、公式、表格和非 `slex` 代码块继续由 Streamdown 渲染。只写状态的 `slex` fence 不渲染独立 UI,但会写入同一 artifact state,供后续可渲染 fence 读取。 最小配置: ```tsx import { Streamdown } from "streamdown"; import { createSlexKitRenderer } from "@slexkit/streamdown"; import "@slexkit/theme-shadcn/style.css"; import "@slexkit/streamdown/style.css"; const slexkitRenderer = createSlexKitRenderer({ domain: "message-1", showChrome: false }); export function Message({ markdown }: { markdown: string }) { return ( {markdown} ); } ``` 如果项目已经以 Streamdown 作为 Markdown 渲染层,使用 `@slexkit/streamdown`。如果宿主有自己的 Markdown parser 或 renderer,直接接入自定义 Markdown host API。 --- # Tiptap 编辑器接入 URL: /zh-CN/examples/tiptap-host Raw Markdown: /zh-CN/examples/tiptap-host.md Source: content/examples/tiptap-host/zh-CN.md # Tiptap 编辑器接入 需要在编辑器中预览 SlexKit 组件时,使用 `@slexkit/tiptap`。该示例复用官网的 RC 低通滤波器内容,演示 SlexKit 组件在 Tiptap 编辑器中的预览方式。 本地运行: ```sh bun run build:core bun run --filter @slexkit/tiptap build bun examples/dev-server.mjs tiptap ``` 源码位于 [`examples/tiptap`](https://github.com/slexkit/slexkit/tree/main/examples/tiptap)。Tiptap 与 Streamdown 示例使用同一份 RC 低通滤波器内容,便于对照编辑器宿主和只读渲染宿主的接入方式。 [打开集成指南](/zh-CN/docs/guides/integration) · [查看可运行源码](https://github.com/slexkit/slexkit/tree/main/examples/tiptap) ## 接入方式 | 项目 | 约定 | | --- | --- | | Block type | `codeBlock` | | Fence language | `slex` | | Runtime | `trusted` | Tiptap 负责文档编辑和 Markdown 导入/导出。只写状态的 `slex` fence 与后续预览块共享 artifact runtime;非 `slex` code block 保持 Tiptap 原生行为。 最小配置: ```ts import { Editor } from "@tiptap/core"; import StarterKit from "@tiptap/starter-kit"; import { Markdown } from "@tiptap/markdown"; import { createSlexKitTiptapExtension } from "@slexkit/tiptap"; import "@slexkit/theme-shadcn/style.css"; import "@slexkit/tiptap/style.css"; const editor = new Editor({ element: document.querySelector("#editor"), extensions: [ StarterKit.configure({ codeBlock: false }), Markdown, createSlexKitTiptapExtension({ artifactId: "doc-1" }) ], content: markdown, contentType: "markdown" }); ``` 需要编辑器内预览时使用 `@slexkit/tiptap`。只读 Markdown 输出通常使用 Streamdown 或自定义 Markdown host API。 --- # Accordion URL: /docs/components/accordion Raw Markdown: /docs/components/accordion.md Source: site/content/components/accordion/en-US.md --- title: "Accordion" category: Disclosure status: ready order: 10 summary: "Multi-panel collapse for FAQs or grouped details." --- # Accordion Manages multiple collapsible panels, with one or more open at a time. ```slex { "slex": "0.1", "namespace": "doc_accordion_typical", "layout": { "accordion:faq": { "multiple": true, "value": [ "install" ], "items": [ { "value": "install", "label": "Install", "icon": "download-simple", "content": "Prepare dependencies." }, { "value": "review", "label": "Review", "icon": "check-circle", "content": "Check the result." }, { "value": "ship", "label": "Ship", "icon": "rocket-launch", "content": "Publish the change." } ] } } } ``` ## Usage Notes - Use for FAQs, grouped details, and collapsible setting lists. - Not suitable for a single expandable area (use `collapsible`). - Related components: `collapsible` for single expandable regions. - Use `$value` and `onchange` for controlled expansion. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `value` | string \| string[] | No | Yes | | Current expanded item value; use an array when multiple is true. | | `multiple` | boolean | No | No | `false` | Allow multiple items to be expanded at the same time. | | `items` | array | No | No | | Panel definitions with value, label, content, and optional icon. | | `items[].icon` | string | No | No | | Icon name shown before an item trigger label. | | `onchange` | write-expression | No | No | | Write expression invoked when expanded items change. | --- # Badge URL: /docs/components/badge Raw Markdown: /docs/components/badge.md Source: site/content/components/badge/en-US.md --- title: "Badge" category: Content status: ready order: 10 summary: "Compact label for status or classification." --- # Badge Compact status label component with semantic tone colors. ```slex { "slex": "0.1", "namespace": "doc_badge_typical", "layout": { "row:badges": { "badge:ready": { "label": "ready", "icon": "check-circle", "tone": "success" }, "badge:pending": { "label": "pending", "tone": "warning" }, "badge:info": { "label": "info", "tone": "info" } } } } ``` ## Usage Notes - Use for status indicators (success / warning / error), classification labels, and count markers. - Not suitable for long text labels (use `callout`) or interactive triggers (use `button`). - Related components: `callout` for titled message blocks, `stat` for numeric metrics. - Multiple badges are typically placed inside a `row`. - Use `tone` only for semantic state, not as an arbitrary style picker. ### Tone variants ```slex { namespace: "doc_badge_tone_diff", layout: { "row:tones": { "badge:info": { label: "info", tone: "info" }, "badge:success": { label: "success", tone: "success" }, "badge:warning": { label: "warning", tone: "warning" }, "badge:danger": { label: "danger", tone: "danger" }, "badge:muted": { label: "muted", tone: "muted" } } } } ``` ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `label` | string | No | Yes | | Badge text. | | `text` | string | No | Yes | | Alias for label. | | `content` | string | No | Yes | | Alias for label. | | `icon` | string | No | No | | Icon name shown before the badge label. | | `tone` | string: info, success, warning, danger, muted | No | No | `"info"` | Semantic tone applied to the badge. | | `variant` | string: info, success, warning, danger, muted | No | No | | Alias for tone. | --- # Button URL: /docs/components/button Raw Markdown: /docs/components/button.md Source: site/content/components/button/en-US.md --- title: "Button" category: Action status: ready order: 10 summary: "Action trigger button." --- # Button Triggers actions in interactive SlexKit layouts. ```slex { "slex": "0.1", "namespace": "doc_button_typical", "layout": { "row:actions": { "button:save": { "label": "Save", "icon": "floppy-disk", "variant": "primary" }, "button:cancel": { "label": "Cancel", "variant": "secondary" }, "button:delete": { "label": "Delete", "variant": "danger" } } } } ``` ## Usage Notes - Use for form submission, confirmation actions, and command triggers. - When `href` is present, the button renders as a button-styled link action; use `link` for ordinary inline navigation. - `selected`, `active`, and `pressed` describe the visual state of the button icon and pressed metadata. - Related components: `link` for navigation instead of actions, `submit` for ToolHost submission flows. - Multiple buttons are typically placed inside a `row`. - Use `variant` only for semantic action types, not as a general style picker. ### Variants ```slex { namespace: "doc_button_variant_diff", layout: { "row:variants": { "button:primary": { label: "Primary", variant: "primary" }, "button:secondary": { label: "Secondary", variant: "secondary" }, "button:danger": { label: "Danger", variant: "danger" }, "button:ghost": { label: "Ghost", variant: "ghost" } } } } ``` ### Disabled state ```slex { namespace: "doc_button_disabled_diff", layout: { "row:disabled": { "button:enabled": { label: "Enabled" }, "button:disabled": { label: "Disabled", disabled: true } } } } ``` ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `label` | string | No | Yes | | Visible button text and accessible name. | | `icon` | string | No | No | | Icon name shown before the label. | | `iconOnly` | boolean | No | No | `false` | Show only the icon while retaining label as the accessible name. | | `variant` | string: primary, secondary, danger, ghost | No | No | `"primary"` | Semantic action variant. | | `disabled` | boolean | No | Yes | `false` | Disable the action. | | `href` | string | No | Yes | | Render the button surface as a link to this URL. | | `target` | string | No | No | | Link target used when href is present. | | `title` | string | No | Yes | | Tooltip and accessible-label fallback. | | `selected` | boolean | No | Yes | | Render the icon in its selected visual state. | | `active` | boolean | No | Yes | | Render the icon in its active visual state. | | `pressed` | boolean | No | Yes | | Expose pressed state and render the selected icon style. | | `onclick` | write-expression | No | No | | Write expression invoked when the button is clicked. | --- # Callout URL: /docs/components/callout Raw Markdown: /docs/components/callout.md Source: site/content/components/callout/en-US.md --- title: "Callout" category: Content status: ready order: 40 summary: "Highlighted contextual message for notes, warnings, and tips." --- # Callout Prominent notice block with title, body text, and semantic tone. ```slex { "slex": "0.1", "namespace": "doc_callout_typical", "layout": { "callout:notice": { "tone": "info", "title": "Notice", "icon": "info", "text": "Use callout for information that should stand out." } } } ``` ## Usage Notes - Use for operation instructions, caution warnings, success prompts, and informational messages. - Not suitable for pure status labels (use `badge`) or interactive content that needs its own flow. - Related components: `badge` for compact labels, `toast` for transient feedback. - Child components can be nested inside a callout to extend the body area. - Use `tone` only for semantic state, not as an arbitrary style picker. ### Tone variants ```slex { namespace: "doc_callout_tone_diff", layout: { "column:tones": { "callout:info": { tone: "info", title: "Info", text: "This is an informational message." }, "callout:success": { tone: "success", title: "Success", text: "Operation completed successfully." }, "callout:warning": { tone: "warning", title: "Warning", text: "Please review before proceeding." }, "callout:danger": { tone: "danger", title: "Danger", text: "This action cannot be undone." } } } } ``` ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `title` | string | No | Yes | | Callout title. | | `heading` | string | No | Yes | | Alias for title. | | `label` | string | No | Yes | | Alias for title. | | `icon` | string | No | No | | Icon name shown before the title. | | `text` | string | No | Yes | | Callout body text. | | `message` | string | No | Yes | | Alias for text. | | `content` | string | No | Yes | | Alias for text. | | `tone` | string: info, success, warning, danger | No | No | `"info"` | Semantic tone for the callout. | | child components | object | No | No | | Nested component fields are rendered as child content in field order. | --- # Card URL: /docs/components/card Raw Markdown: /docs/components/card.md Source: site/content/components/card/en-US.md --- title: "Card" category: Layout status: ready order: 50 summary: "Grouping container for related content." --- # Card Card-style container with optional title and semantic tone. ```slex { "slex": "0.1", "namespace": "doc_card_typical", "layout": { "card:metrics": { "title": "Metrics", "icon": "chart-bar", "grid:items": { "columns": 2, "stat:requests": { "label": "Requests", "value": "1.2k", "unit": "/min" }, "stat:latency": { "label": "Latency", "value": "42", "unit": "ms" } } } } } ``` ## Usage Notes - Use for grouped metrics, settings blocks, and information summaries. - Not suitable for page-level section headers (use `section`) or pure layout containers (use `column` or `grid`). - Related components: `section` provides a complete page block structure (title + subtitle + action), while `card` is more lightweight. - Child components arrange naturally inside a card; nest `row`, `column`, or `grid`. - Use `tone` only for semantic state, not as an arbitrary style picker. ### Tone variants ```slex { namespace: "doc_card_tone_diff", layout: { "row:tones": { "card:info": { title: "Info", tone: "info", "text:body": { text: "Information card." } }, "card:success": { title: "Success", tone: "success", "text:body": { text: "Success card." } }, "card:warning": { title: "Warning", tone: "warning", "text:body": { text: "Warning card." } } } } } ``` ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `title` | string | No | Yes | | Card title. | | `icon` | string | No | No | | Icon name shown before the title. | | `tone` | string: info, success, warning, danger, muted | No | No | | Optional semantic tone for the card surface. | | `variant` | string: tool | No | No | | Use tool for ToolHost input cards with compact chrome. | | child components | object | No | No | | Nested component fields are rendered as child content in field order. | --- # Checkbox URL: /docs/components/checkbox Raw Markdown: /docs/components/checkbox.md Source: site/content/components/checkbox/en-US.md --- title: "Checkbox" category: Input status: ready order: 30 summary: "Boolean checkbox for confirmations and multi-select." --- # Checkbox Boolean toggle for confirmation or multi-select scenarios. ```slex { "slex": "0.1", "namespace": "doc_checkbox_typical", "layout": { "checkbox:agree": { "checked": true, "label": "I agree", "icon": "handshake" } } } ``` ## Usage Notes - Use for terms agreement, multi-select settings, and per-item enable/disable. - Not suitable for instant-activation toggles (use `switch`) or mutually exclusive options (use `radio-group`). - Related components: `switch` for instant effect toggles, `radio-group` for exclusive options. - Multiple options are typically arranged vertically inside a `column`. - Use `$checked` and `onchange` for state binding. ### Checked / disabled states ```slex { namespace: "doc_checkbox_state_diff", layout: { "column:diff": { "checkbox:checked": { label: "Checked", checked: true }, "checkbox:unchecked": { label: "Unchecked" }, "checkbox:disabled-checked": { label: "Disabled checked", checked: true, disabled: true }, "checkbox:disabled": { label: "Disabled", disabled: true } } } } ``` ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `checked` | boolean | No | Yes | `false` | Checked state. | | `label` | string | No | Yes | | Checkbox label. | | `icon` | string | No | No | | Icon name shown before the visible label. | | `disabled` | boolean | No | Yes | `false` | Disable the checkbox. | | `haptic` | boolean | No | No | `true` | Enable vibration feedback on supported devices. | | `haptics` | boolean | No | No | `true` | Alias for haptic. | | `onchange` | write-expression | No | No | | Write expression invoked when checked state changes. | --- # Code Block URL: /docs/components/code-block Raw Markdown: /docs/components/code-block.md Source: site/content/components/code-block/en-US.md --- title: "Code Block" category: Content status: ready order: 50 summary: "Code or configuration snippet display." --- # Code Block Display code, configuration, or source snippets with a language label and optional title. ```slex { "slex": "0.1", "namespace": "doc_code_block_typical", "layout": { "code-block:config": { "title": "Config", "icon": "code", "language": "js", "code": "export const enabled = true;" } } } ``` ## Usage Notes - Use for code samples, JSON config, CLI snippets, and log output. - Not suitable for runnable SlexKit examples (use `slex` fence or `playground`). - Related components: `playground` for editable interactive previews. - Code content is display-only; editing is not supported. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `code` | string | No | Yes | | Code text content. | | `source` | string | No | Yes | | Alias for code. | | `content` | string | No | Yes | | Alias for code. | | `language` | string | No | No | | Language label. | | `title` | string | No | No | | Code block title. | | `icon` | string | No | No | | Icon name shown before the title. | | `lineNumbers` | boolean | No | No | `true` | Show line numbers. | --- # Collapsible URL: /docs/components/collapsible Raw Markdown: /docs/components/collapsible.md Source: site/content/components/collapsible/en-US.md --- title: "Collapsible" category: Disclosure status: ready order: 20 summary: "Single expandable content area." --- # Collapsible Manages a single expand/collapse region for supplementary details or secondary information. ```slex { "slex": "0.1", "namespace": "doc_collapsible_typical", "layout": { "collapsible:more": { "open": true, "trigger": "Details", "icon": "caret-circle-down", "content": "This secondary content can be collapsed." } } } ``` ## Usage Notes - Use for expandable details, supplementary notes, and collapsible secondary info. - Not suitable for multi-panel lists (use `accordion`). - Related components: `accordion` for multi-panel collapse. - Child components extend the default body content area. - Use `$value` and `onchange` for controlled expansion. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `open` | boolean | No | Yes | `false` | Expanded state. | | `trigger` | string | No | Yes | | Trigger button text. | | `icon` | string | No | No | | Icon name shown before trigger text. | | `content` | string | No | Yes | | Static body content. | | `onchange` | write-expression | No | No | | Write expression invoked when open state changes. | | child components | object | No | No | | Nested component fields are rendered as child content in field order. | --- # Column URL: /docs/components/column Raw Markdown: /docs/components/column.md Source: site/content/components/column/en-US.md --- title: "Column" category: Layout status: ready order: 20 summary: "Vertical layout container for forms, text, and control groups." --- # Column Basic vertical layout container. ```slex { "slex": "0.1", "namespace": "doc_column_typical", "layout": { "column:form": { "input:name": { "placeholder": "Name" }, "input:email": { "placeholder": "Email" }, "button:save": { "label": "Save" } } } } ``` ## Usage Notes - Use for form field groups, settings panels, description text, and sequences of actions. - Not suitable for horizontal layouts (use `row`) or equal-width card grids (use `grid`). - Related components: `row` for horizontal layout, `grid` for two-dimensional equal-width layout. - Place child components as fields, stacked top-to-bottom. - Default width fills the parent container; height is content-driven. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | child components | object | No | No | | Nested component fields are rendered as child content in field order. | --- # Divider URL: /docs/components/divider Raw Markdown: /docs/components/divider.md Source: site/content/components/divider/en-US.md --- title: "Divider" category: Content status: ready order: 35 summary: "Separator line, optionally with label." --- # Divider Horizontal separator, optionally with a centered text label. ```slex { "slex": "0.1", "namespace": "doc_divider_typical", "layout": { "column:content": { "text:top": { "text": "Above" }, "divider:line": { "label": "Divider", "icon": "flag" }, "text:bottom": { "text": "Below" } } } } ``` ## Usage Notes - Use for form sections, settings groups, and visual separation between content paragraphs. - Not suitable as a spacing mechanism (use layout container `gap`). - Related components: `section` for more structured block separation. - Place inside a `column` to separate upper and lower content areas. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `label` | string | No | Yes | | Text shown in the divider. | | `icon` | string | No | No | | Icon name shown before the label. | --- # Formula URL: /docs/components/formula Raw Markdown: /docs/components/formula.md Source: site/content/components/formula/en-US.md --- title: "Formula" category: Display status: ready order: 11 summary: "Reactive KaTeX formula display." --- # Formula Render SlexKit state and computed values through KaTeX. Use it when Markdown explains the model and the interactive block needs the formula itself to update. ```slex { "slex": "0.1", "namespace": "doc_formula_typical", "g": { "r": 10000, "c": 100, "fc": 159.15 }, "layout": { "formula:cutoff": { "$tex": "'f_c = \\\\frac{1}{2\\\\pi RC} = ' + g.fc + '\\\\text{ Hz}'" } } } ``` ## Usage Notes - Use for formulas whose variables come from SlexKit state. - Keep the explanatory derivation in Markdown and use `formula` for the live expression. - Use `displayMode: false` for inline formula fragments. - Invalid TeX is rendered by KaTeX as an error expression instead of throwing. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `tex` | string | No | Yes | | KaTeX source to render. | | `formula` | string | No | Yes | | Alias for tex. | | `value` | string | No | Yes | | Alias for tex. | | `displayMode` | boolean | No | No | `true` | Render as display math when true; inline math when false. | | `display` | boolean | No | No | `true` | Alias for displayMode. | | `block` | boolean | No | No | `true` | Alias for displayMode. | --- # Grid URL: /docs/components/grid Raw Markdown: /docs/components/grid.md Source: site/content/components/grid/en-US.md --- title: "Grid" category: Layout status: ready order: 40 summary: "Responsive equal-width grid for sibling cards, metrics, and field groups." --- # Grid Responsive equal-width column layout with breakpoint-prefixed column count. ```slex { "slex": "0.1", "namespace": "doc_grid_typical", "layout": { "grid:stats": { "columns": 1, "mdColumns": 3, "stat:a": { "label": "Requests", "value": "1.2k" }, "stat:b": { "label": "Success", "value": "98%" }, "stat:c": { "label": "Errors", "value": "3" } } } } ``` ## Usage Notes - Use for metric dashboards, card lists, and horizontal equal-width groups of form fields. - Not suitable for mixed-width layouts (use `row` + `column` combinations) or single-column arrangements (use `column`). - Related components: `row` for horizontal layout without equal-width guarantees, `column` for vertical layout. - Child components are automatically equal-width — best for same-level content. - Use `gap` to override the spacing; when omitted, the grid keeps its theme CSS default. ### Column variants ```slex { namespace: "doc_grid_columns_diff", layout: { "column:demo": { "text:cols2": { text: "columns: 2" }, "grid:cols2": { columns: 2, "stat:a": { label: "A", value: "1" }, "stat:b": { label: "B", value: "2" }, "stat:c": { label: "C", value: "3" } }, "text:cols3": { text: "columns: 3" }, "grid:cols3": { columns: 3, "stat:a": { label: "A", value: "1" }, "stat:b": { label: "B", value: "2" }, "stat:c": { label: "C", value: "3" } } } } } ``` ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `columns` | number | No | Yes | `1` | Base column count. | | `smColumns` | number | No | Yes | | Column count at the small breakpoint. | | `mdColumns` | number | No | Yes | | Column count at the medium breakpoint. | | `lgColumns` | number | No | Yes | | Column count at the large breakpoint. | | `xlColumns` | number | No | Yes | | Column count at the extra-large breakpoint. | | `gap` | string | No | Yes | | Spacing between grid items. | | child components | object | No | No | | Nested component fields are rendered as child content in field order. | --- # Icon URL: /docs/components/icon Raw Markdown: /docs/components/icon.md Source: site/content/components/icon/en-US.md --- title: "Icon" category: Component status: ready order: 10 summary: "Shared icon field capability used by all icon-supporting components." --- # Icon Icon is not a standalone layout component — it is a component field capability. Components that support the `icon` field resolve icon names through the global icon manager and place the resulting SVG in their own visual position. ```slex { "slex": "0.1", "namespace": "spec_button_basic", "layout": { "button:demo": { "label": "Settings", "icon": "gear-six", "iconOnly": true, "variant": "ghost" } } } ``` ## Supported components | Component | Field | Description | | --- | --- | --- | | accordion | `items[].icon` | Icon before each accordion item trigger label. | | badge | `icon` | Icon before the badge text. | | button | `icon`, `iconOnly` | Icon before the button label; `iconOnly: true` shows only the icon while still requiring `label`. | | callout | `icon` | Icon before the callout title. | | card | `icon` | Icon before the card title. | | checkbox | `icon` | Icon before the visible checkbox label. | | code-block | `icon` | Icon before the code block title. | | collapsible | `icon` | Icon before the collapsible trigger text. | | divider | `icon` | Icon before the divider label text. | | link | `icon` | Icon before the link text. | | progress | `icon` | Icon before the progress label. | | radio-group | `icon`, `options[].icon` | Icon before the group label and each option label. | | section | `icon` | Icon before the section title. | | select | `icon`, `options[].icon` | `icon` decorates the top label; `options[].icon` decorates menu options and the selected value. | | slider | `icon` | Icon before the slider label. | | stat | `icon` | Icon before the metric label. | | switch | `icon` | Icon before the visible switch label. | | table | `columns[].icon` | Icon before each table column header label. | | tabs | `tabs[].icon`, `tabs[].iconOnly` | Icon in each tab trigger; selected tab may request an active variant. | | toast | `icon` | Replaces the default left semantic marker with an icon while retaining tone color. | `playground` internally reuses button for its toolbar actions, so it benefits from the same icon manager, but it does not expose a public `icon` field. `select`'s dropdown arrow is a fixed control indicator; `select.icon` only decorates the top label, not the dropdown arrow. ## Name resolution Unprefixed icon names default to Iconify's `ph` collection (Phosphor icons). ```slex { namespace: "doc_icon_names", layout: { "row:icons": { "button:chart": { label: "Chart", icon: "ChartBar" }, "button:copy": { label: "Copy", icon: "lucide:copy", variant: "secondary" }, "button:settings": { label: "Settings", icon: "gear-six", iconOnly: true, variant: "ghost" } } } } ``` Common syntax: | Syntax | Resolves to | | ----------------- | ---------------------------------------- | | `ChartBar` | `ph:chart-bar` | | `chart-bar` | `ph:chart-bar` | | `ph:chart-bar` | Phosphor / Iconify `ph` collection | | `lucide:copy` | Iconify `lucide` collection | | `brand:logo-mark` | Custom icon registered by the host via `registerIcon` | ## Tabs with icons ```slex { namespace: "doc_icon_tabs", layout: { "tabs:main": { value: "overview", tabs: [ { value: "overview", label: "Overview", icon: "ChartBar" }, { value: "activity", label: "Activity", icon: "pulse" }, { value: "settings", label: "Settings", icon: "Gear", iconOnly: true } ] } } } ``` ## Label and title icons ```slex { namespace: "doc_icon_labels", layout: { "column:demo": { "callout:notice": { title: "Notice", icon: "info", text: "Title-bearing components can use the same icon field." }, "accordion:faq": { value: "install", items: [ { value: "install", label: "Install", icon: "download-simple", content: "Prepare dependencies." }, { value: "review", label: "Review", icon: "check-circle", content: "Verify the result." } ] }, "select:env": { label: "Environment", icon: "server", value: "prod", options: [ { label: "Development", value: "dev", icon: "code" }, { label: "Production", value: "prod", icon: "rocket-launch" } ] }, "radio-group:mode": { label: "Mode", icon: "sliders-horizontal", value: "auto", options: [ { label: "Auto", value: "auto", icon: "sparkle" }, { label: "Manual", value: "manual", icon: "wrench" } ] } } } } ``` ## Custom icons Hosts can register their own SVG icons before mounting content. Once registered, all components that support the `icon` field can use them by name. ```js import { registerIcon, registerIcons } from "slexkit"; registerIcon( "brand:logo-mark", '', { aliases: ["logo-mark"] }, ); registerIcons({ "status:healthy": '', }); ``` ## Usage rules - `iconOnly` is supported on `button` and `tabs` only; titles, labels, and column headers never hide text. - `iconOnly` must be paired with `label`, `title`, or `aria-label` — assistive technology needs a readable name. - Without a prefix, prefer Phosphor semantic names; use an explicit prefix such as `lucide:copy` for cross-icon-set usage. - The runtime does not accept arbitrary URLs as icon sources. Remote icons are fetched via the Iconify API and the returned SVG passes through basic filtering. - Bundled icons display synchronously on first paint; unbundled icons load asynchronously. When the network is unavailable, components retain their text content. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `icon` | string | No | No | | Icon name resolved through the global icon manager. | | `iconOnly` | boolean | No | No | | Render only the icon while retaining an accessible label where supported. | | `items[].icon` | string | No | No | | Accordion item trigger icon. | | `options[].icon` | string | No | No | | Select or radio option icon. | | `columns[].icon` | string | No | No | | Table column header icon. | | `tabs[].icon` | string | No | No | | Tab trigger icon. | | `tabs[].iconOnly` | boolean | No | No | | Tab trigger icon-only mode. | --- # Input URL: /docs/components/input Raw Markdown: /docs/components/input.md Source: site/content/components/input/en-US.md --- title: "Input" category: Input status: ready order: 10 summary: "Single-line text or engineering value input." --- # Input Single-line text input with controlled value, placeholder, label, description, native types, engineering input, and disabled state. ```slex { "slex": "0.1", "namespace": "doc_input_typical", "layout": { "input:name": { "label": "Project", "value": "SlexKit", "placeholder": "Enter name", "description": "Visible labels keep form fields scannable." } } } ``` ## Usage Notes - Use for name input, search boxes, email/password, and other single-line text. - Use `type: "engineering"` for values such as `4.7k`, `2.2uF`, or `1e-3`. - Not suitable for numeric range selection (use `slider`). - Related components: `select` for option selection, `slider` for numeric ranges. - Typically placed inside a `column` to compose forms. - Use `$value` and `onchange` for state binding. - Numeric and engineering inputs render only the native input. Use `slider` for range adjustment; SlexKit no longer adds custom decrement or increment buttons. - `onchange` fires when the user edits the value. - `type: "number"` still emits a string value. Convert with `Number($event)` or use `type: "engineering"` to read parsed results. - Use `invalid` plus `error` for validation feedback. Error text is linked through `aria-describedby`. ### Label and unit `label` renders as a clickable native label; `unit` renders as trailing text, suitable for voltage, resistance, frequency, etc. ```slex { namespace: "doc_input_label_unit", layout: { "input:voltage": { label: "Voltage", value: "3.3", unit: "V", description: "Supply rail" } } } ``` ### Disabled state ```slex { namespace: "doc_input_disabled_diff", layout: { "row:diff": { "input:enabled": { value: "Editable", placeholder: "Type here" }, "input:disabled": { value: "Disabled", disabled: true } } } } ``` ### Engineering input `type: "engineering"` uses a text input (not the native number type). Component state retains the raw string and additionally exposes parsed results: ```slex { namespace: "doc_input_engineering", layout: { "input:resistance": { type: "engineering", value: "4.7kΩ" }, "stat:parsed": { label: "Parsed value", $value: "resistance.valid ? resistance.number : 'Invalid'", $unit: "resistance.unit" } } } ``` Supports scientific notation and SI prefixes: `p`, `n`, `u`, `µ`, `m`, `k`, `K`, `M`, `meg`, `G`, `T`. Units are captured but not converted across physical dimensions. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `value` | string | No | Yes | | Current input value. | | `label` | string | No | Yes | | Input label. | | `unit` | string | No | Yes | | Trailing unit text. | | `description` | string | No | Yes | | Assistive description below the input. | | `help` | string | No | Yes | | Alias for description. | | `hint` | string | No | Yes | | Alias for description. | | `error` | string | No | Yes | | Error text shown below the input and linked with aria-describedby. | | `errorMessage` | string | No | Yes | | Alias for error. | | `invalid` | boolean | No | Yes | `false` | Mark the input as invalid with aria-invalid and error styling. | | `placeholder` | string | No | No | | Placeholder text for empty values. | | `type` | string | No | No | `"text"` | Input value kind; use engineering for parsed engineering values. | | `disabled` | boolean | No | Yes | `false` | Disable editing. | | `readonly` | boolean | No | Yes | `false` | Make the input read-only. | | `readOnly` | boolean | No | Yes | `false` | Alias for readonly. | | `required` | boolean | No | Yes | `false` | Mark the input as required. | | `id` | string | No | No | | Native input id; defaults to a stable id derived from the component name. | | `name` | string | No | No | | Native input name attribute. | | `min` | string \| number | No | Yes | | Minimum value used by numeric input controls. | | `max` | string \| number | No | Yes | | Maximum value used by numeric input controls. | | `step` | string \| number | No | Yes | | Step size used by numeric input controls. | | `onchange` | write-expression | No | No | | Write expression invoked when the value changes. | --- # Link URL: /docs/components/link Raw Markdown: /docs/components/link.md Source: site/content/components/link/en-US.md --- title: "Link" category: Content status: ready order: 25 summary: "Navigation or lightweight jump action." --- # Link Text link navigation. ```slex { "slex": "0.1", "namespace": "doc_link_typical", "layout": { "column:links": { "link:docs": { "href": "/components", "icon": "arrow-square-out", "text": "View components" } } } } ``` ## Usage Notes - Use for page navigation, external links, and inline text links. - Not suitable for primary action buttons (use `button`). - Related components: `button` for explicit action triggers. - Keep link text short. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `href` | string | No | No | | Target URL. | | `text` | string | No | Yes | | Visible link text. | | `label` | string | No | Yes | | Alias for text. | | `content` | string | No | Yes | | Alias for text. | | `icon` | string | No | No | | Icon name shown before link text. | | `target` | string | No | No | | Native link target attribute. | | `variant` | string: default, muted | No | No | `"default"` | Link visual variant. | --- # Playground URL: /docs/components/playground Raw Markdown: /docs/components/playground.md Source: site/content/components/playground/en-US.md --- title: "Playground" category: Tooling status: ready order: 10 summary: "Interactive preview and editor for SlexKit / Markdown source." --- # Playground Interactive preview component that embeds editable, runnable SlexKit or Markdown source previews inside a page. ```slex { "slex": "0.1", "namespace": "doc_playground_typical", "layout": { "playground:demo": { "title": "Stat Playground", "previewMinHeight": "180px", "source": { "namespace": "inner_stat_demo", "layout": { "stat:value": { "label": "Requests", "value": "1.2k", "unit": "/min" } } } } } } ``` ## Usage Notes - Use for runnable examples in documentation, interactive demos, and source code teaching. - Not suitable for ordinary component rendering (use layout components directly). - Related components: `code-block` for read-only code display. - Nested source is rendered in an isolated scope — it does not conflict with the parent namespace. - Use Playground for documentation and teaching surfaces, not product UI. - Public fields cover source parsing, preview placement, theme toggle controls, labels, and open/copy URLs. - `domain`, `pluginVersion`, and `version` are host integration metadata, not public component fields. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `source` | object \| string | No | No | | SlexKit or Markdown source to preview. | | `sourceType` | string: slex, markdown, auto-markdown | No | No | `"slex"` | Source parser mode. | | `title` | string | No | No | | Playground title. | | `previewAlign` | string: center, start | No | No | `"center"` | Vertical preview alignment in render mode. | | `alignPreview` | string: center, start | No | No | | Alias for previewAlign. | | `previewPlacement` | string: center, start | No | No | | Alias for previewAlign. | | `previewMinHeight` | string | No | No | | Minimum preview area height. | | `previewMaxWidth` | string | No | No | | Maximum preview content width. | | `themeToggle` | boolean | No | No | `false` | Show the theme toggle action. | | `showThemeToggle` | boolean | No | No | `false` | Alias for themeToggle. | | `enableThemeToggle` | boolean | No | No | `false` | Alias for themeToggle. | | `themeLabel` | string | No | No | | Accessible label for the theme toggle action. | | `themeToggleLabel` | string | No | No | | Alias for themeLabel. | | `sourceTypeLabel` | string | No | No | | Accessible label for the source type selector. | | `copyLabel` | string | No | No | | Accessible label for the copy source action. | | `openWebLabel` | string | No | No | | Accessible label for opening the source in the standalone playground. | | `webUrl` | string | No | No | | Standalone playground URL used by the open action. | | `playgroundUrl` | string | No | No | | Alias for webUrl. | --- # Progress URL: /docs/components/progress Raw Markdown: /docs/components/progress.md Source: site/content/components/progress/en-US.md --- title: "Progress" category: Feedback status: ready order: 10 summary: "Progress bar." --- # Progress Display task completion progress controlled by value. ```slex { "slex": "0.1", "namespace": "doc_progress_typical", "layout": { "progress:build": { "label": "Build progress", "icon": "gear-six", "value": 64 } } } ``` ## Usage Notes - Use for build progress, upload progress, and task completion. - Not suitable for indeterminate waiting states. - Related components: `stat` for numeric metric display. - Value range is 0-100. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `value` | number | No | Yes | `0` | Progress percentage from 0 to 100. | | `label` | string | No | Yes | | Progress label. | | `icon` | string | No | No | | Icon name shown before the label. | | `indeterminate` | boolean | No | Yes | `false` | Render an indeterminate progress state without aria-valuenow. | --- # Radio Group URL: /docs/components/radio-group Raw Markdown: /docs/components/radio-group.md Source: site/content/components/radio-group/en-US.md --- title: "Radio Group" category: Input status: ready order: 70 summary: "Mutually exclusive radio selection." --- # Radio Group Mutually exclusive option selection for small choice sets. ```slex { "slex": "0.1", "namespace": "doc_radio_group_typical", "layout": { "radio-group:mode": { "label": "Mode", "icon": "sliders-horizontal", "value": "auto", "options": [ { "label": "Auto", "value": "auto", "icon": "sparkle" }, { "label": "Manual", "value": "manual", "icon": "wrench" } ] } } } ``` ## Usage Notes - Use for mode selection, small enum choices, and mutually exclusive config items. - Not suitable for many options (use `select`). - Related components: `select` for dropdown single selection with more options. - Keep options between 2-5 items. - Use `$value` and `onchange` for state binding. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `value` | string | No | Yes | | Current selected value. | | `label` | string | No | Yes | | Group label. | | `icon` | string | No | No | | Icon name shown before the group label. | | `options` | array | No | No | | Options with label, value, and optional icon. | | `options[].icon` | string | No | No | | Icon name shown before a single option label. | | `options[].description` | string | No | No | | Secondary text shown below the option label. | | `disabled` | boolean | No | Yes | `false` | Disable every radio option in the group. | | `orientation` | string: vertical, horizontal | No | No | `"vertical"` | Radio option layout direction. | | `variant` | string: list | No | No | | Use list for full-row option surfaces in ToolHost decision cards. | | `haptic` | boolean | No | No | `true` | Enable vibration feedback on supported devices. | | `haptics` | boolean | No | No | `true` | Alias for haptic. | | `name` | string | No | No | | Native radio group name shared by options. | | `onchange` | write-expression | No | No | | Write expression invoked when selection changes. | --- # Row URL: /docs/components/row Raw Markdown: /docs/components/row.md Source: site/content/components/row/en-US.md --- title: "Row" category: Layout status: ready order: 30 summary: "Horizontal layout container for toolbars, status lines, and button groups." --- # Row Basic horizontal layout container. ```slex { "slex": "0.1", "namespace": "doc_row_typical", "layout": { "row:toolbar": { "justify": "space-between", "text:title": { "text": "Runtime status" }, "button:refresh": { "label": "Refresh" } } } } ``` ## Usage Notes - Use for button groups, toolbars, status indicator lines, and table header actions. - Not suitable for vertical form fields (use `column`) or equal-width card grids (use `grid`). - Related components: `column` for vertical layout, `grid` for two-dimensional equal-width layout. - Children arrange at natural width; use `justify` to control distribution. - Use `gap` to override the spacing between children; when omitted, the row keeps its theme CSS default. ### Justify variants ```slex { namespace: "doc_row_justify_diff", layout: { "column:demo": { "text:start": { text: "justify: start" }, "row:justify-start": { justify: "start", "badge:a": { label: "A" }, "badge:b": { label: "B" } }, "text:center": { text: "justify: center" }, "row:justify-center": { justify: "center", "badge:a": { label: "A" }, "badge:b": { label: "B" } }, "text:end": { text: "justify: end" }, "row:justify-end": { justify: "end", "badge:a": { label: "A" }, "badge:b": { label: "B" } }, "text:space-between": { text: "justify: space-between" }, "row:justify-between": { justify: "space-between", "badge:a": { label: "A" }, "badge:b": { label: "B" } } } } } ``` ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `justify` | string: start, center, end, space-between, space-around | No | No | `"start"` | Main-axis distribution. | | `align` | string: start, center, end, baseline, stretch | No | No | `"center"` | Cross-axis alignment. | | `gap` | string | No | Yes | | Spacing between children. | | `variant` | string: actions | No | No | | Use actions for compact ToolHost action rows. | | child components | object | No | No | | Nested component fields are rendered as child content in field order. | --- # Section URL: /docs/components/section Raw Markdown: /docs/components/section.md Source: site/content/components/section/en-US.md --- title: "Section" category: Layout status: ready order: 60 summary: "Page section with title, subtitle, optional action, and content area." --- # Section Page-level block container with title, subtitle, optional action link, and content area. ```slex { "slex": "0.1", "namespace": "doc_section_typical", "layout": { "section:overview": { "eyebrow": "Dashboard", "title": "Runtime overview", "icon": "chart-bar", "subtitle": "This section groups the most important state.", "stat:latency": { "label": "Latency", "value": "42", "unit": "ms" } } } } ``` ## Usage Notes - Use for dashboard blocks, settings groups, and categorized content areas. - Not suitable for purely visual cards (use `card`) or untitled containers (use `column`). - Related components: `card` is a lighter grouping container, while `section` provides a more complete heading structure. - The heading area and content area are distinct; nest any layout component inside the content area. ### Eyebrow / subtitle variants ```slex { namespace: "doc_section_eyebrow_diff", layout: { "column:demo": { "section:with-eyebrow": { eyebrow: "Overview", title: "With eyebrow", "text:body": { text: "Eyebrow appears above the title." } }, "section:with-subtitle": { title: "With subtitle", subtitle: "Additional context below the title.", "text:body": { text: "Subtitle provides extra context." } } } } } ``` ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `title` | string | No | Yes | | Section title. | | `icon` | string | No | No | | Icon name shown before the title. | | `eyebrow` | string | No | Yes | | Small label above the title. | | `subtitle` | string | No | Yes | | Subtitle text below the title. | | `actionLabel` | string | No | Yes | | Optional action link label. | | `actionHref` | string | No | No | | Optional action link target. | | child components | object | No | No | | Nested component fields are rendered as child content in field order. | --- # Select URL: /docs/components/select Raw Markdown: /docs/components/select.md Source: site/content/components/select/en-US.md --- title: "Select" category: Input status: ready order: 20 summary: "Single-select dropdown." --- # Select Single-select dropdown with options defined as an array and the current value controlled via value. ```slex { "slex": "0.1", "namespace": "doc_select_typical", "layout": { "select:env": { "label": "Environment", "icon": "server", "value": "prod", "options": [ { "label": "Development", "value": "dev", "icon": "code" }, { "label": "Production", "value": "prod", "icon": "rocket-launch" } ] } } } ``` ## Usage Notes - Use for enum selection, config items, and environment choice. - Not suitable for small mutually exclusive groups (use `radio-group`). - Related components: `radio-group` for smaller option sets. - Combine with `column` to compose forms. - Use `$value` and `onchange` for state binding. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `label` | string | No | Yes | | Select label. | | `icon` | string | No | No | | Icon name shown before the top label. | | `value` | string | No | Yes | | Current selected value. | | `options` | array | No | No | | Options with label, value, and optional icon. | | `options[].icon` | string | No | No | | Icon name shown before an option label. | | `placeholder` | string | No | No | | Placeholder shown when no value is selected. | | `disabled` | boolean | No | Yes | `false` | Disable the select trigger and native select. | | `required` | boolean | No | Yes | `false` | Require a non-placeholder value in the native select. | | `variant` | string: default, toolbar | No | No | `"default"` | Select surface variant. | | `onchange` | write-expression | No | No | | Write expression invoked when selection changes. | --- # Slider URL: /docs/components/slider Raw Markdown: /docs/components/slider.md Source: site/content/components/slider/en-US.md --- title: "Slider" category: Input status: ready order: 60 summary: "Numeric range input." --- # Slider Numeric range selection with min, max, step control and unit display. ```slex { "slex": "0.1", "namespace": "doc_slider_typical", "layout": { "slider:volume": { "label": "Volume", "icon": "speaker-high", "value": 42, "min": 0, "max": 100, "step": 1, "unit": "%" } } } ``` ## Usage Notes - Use for volume, brightness, threshold, and percentage adjustments. - Not suitable for precise text entry (use `input`). - Related components: `input` for text input. - Use `$value` and `onchange` for state binding. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `label` | string | No | Yes | | Slider label. | | `icon` | string | No | No | | Icon name shown before the label. | | `value` | number | No | Yes | `0` | Current numeric value. | | `min` | number | No | Yes | `0` | Minimum value. | | `max` | number | No | Yes | `100` | Maximum value. | | `step` | number | No | Yes | `1` | Step interval. | | `unit` | string | No | Yes | | Unit shown after the value. | | `disabled` | boolean | No | Yes | `false` | Disable the range input. | | `orientation` | string: horizontal, vertical | No | No | `"horizontal"` | Slider orientation metadata used for styling. | | `haptic` | boolean | No | No | `true` | Enable vibration feedback on supported devices. | | `haptics` | boolean | No | No | `true` | Alias for haptic. | | `onchange` | write-expression | No | No | | Write expression invoked when the value changes. | --- # Stat URL: /docs/components/stat Raw Markdown: /docs/components/stat.md Source: site/content/components/stat/en-US.md --- title: "Stat" category: Display status: ready order: 10 summary: "Metric display with label, value, unit, and semantic tone." --- # Stat Present a labeled metric value with optional unit and semantic tone. ```slex { "slex": "0.1", "namespace": "doc_stat_typical", "layout": { "grid:stats": { "columns": 2, "stat:requests": { "label": "Requests", "icon": "activity", "value": "1.2k", "unit": "/min" }, "stat:success": { "label": "Success", "icon": "check-circle", "value": "98.4", "unit": "%", "tone": "success" } } } } ``` ## Usage Notes - Use for data dashboards, metric overviews, and key indicator displays. - Not suitable for long text (use `text`) or interactive input (use `input`). - Related components: `text` for text output, `badge` for label status. - Stats are typically used inside a `grid` or `row`. - Use `tone` only for semantic state, not as an arbitrary style picker. ### Tone variants ```slex { namespace: "doc_stat_tone_diff", layout: { "row:tones": { "stat:info": { label: "Info", value: "42", tone: "info" }, "stat:success": { label: "Success", value: "98%", tone: "success" }, "stat:warning": { label: "Warning", value: "73", tone: "warning" }, "stat:danger": { label: "Danger", value: "5", tone: "danger" }, "stat:muted": { label: "Muted", value: "0", tone: "muted" } } } } ``` ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `label` | string | No | Yes | | Metric label. | | `icon` | string | No | No | | Icon name shown before the label. | | `value` | string \| number | No | Yes | | Metric value. | | `unit` | string | No | Yes | | Unit shown after the value. | | `tone` | string: info, success, warning, danger, muted | No | No | | Optional semantic tone. | | `animateInitial` | boolean | No | No | `false` | Animate the initial rendered value. | --- # Switch URL: /docs/components/switch Raw Markdown: /docs/components/switch.md Source: site/content/components/switch/en-US.md --- title: "Switch" category: Input status: ready order: 40 summary: "Boolean toggle input for instant settings." --- # Switch Boolean toggle for instant-activation settings. ```slex { "slex": "0.1", "namespace": "doc_switch_typical", "layout": { "switch:feature": { "enabled": true, "label": "Enable sync", "icon": "arrows-clockwise" } } } ``` ## Usage Notes - Use for feature toggles, preference enable/disable, and instant-effect settings. - Not suitable for confirmation-style toggles (use `checkbox`). - Related components: `checkbox` for confirmations or multi-select. - Typically placed inside a `row` or `column`. - Use `$enabled` and `onchange` for state binding. ### Enabled / disabled variants ```slex { namespace: "doc_switch_state_diff", layout: { "row:diff": { "switch:enabled": { label: "Enabled", enabled: true }, "switch:disabled": { label: "Disabled" }, "switch:enabled-not-available": { label: "Enabled (not available)", enabled: true, disabled: true }, "switch:disabled-not-available": { label: "Disabled (not available)", disabled: true } } } } ``` ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `enabled` | boolean | No | Yes | `false` | Enabled state. | | `label` | string | No | Yes | | Switch label. | | `icon` | string | No | No | | Icon name shown before the visible label. | | `disabled` | boolean | No | Yes | `false` | Disable the switch. | | `haptic` | boolean | No | No | `true` | Enable vibration feedback on supported devices. | | `haptics` | boolean | No | No | `true` | Alias for haptic. | | `onchange` | write-expression | No | No | | Write expression invoked when enabled state changes. | --- # Table URL: /docs/components/table Raw Markdown: /docs/components/table.md Source: site/content/components/table/en-US.md --- title: "Table" category: Data status: ready order: 10 summary: "Structured table with columns and rows." --- # Table Structured row-column data display with column headers and data rows. ```slex { "slex": "0.1", "namespace": "doc_table_typical", "layout": { "table:routes": { "columns": [ { "key": "name", "label": "Name", "icon": "text-t" }, { "key": "status", "label": "Status", "icon": "check-circle" } ], "rows": [ { "name": "Parse", "status": "ready" }, { "name": "Publish", "status": "pending" } ] } } } ``` ## Usage Notes - Use for data lists, configuration tables, and structured information display. - Not suitable for card-style layouts (use `grid`). - Related components: `grid` for equal-width card layouts. - Column `key` values correspond to field names in each row. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `columns` | array | No | No | | Column definitions with key, label, and optional icon. | | `columns[].icon` | string | No | No | | Icon name shown before a column label. | | `rows` | array | No | No | | Row data objects keyed by column key. | | `items` | array | No | No | | Alias for rows. | --- # Tabs URL: /docs/components/tabs Raw Markdown: /docs/components/tabs.md Source: site/content/components/tabs/en-US.md --- title: "Tabs" category: Navigation status: ready order: 10 summary: "Tabbed view switcher." --- # Tabs Switch between named content panels. ```slex { "slex": "0.1", "namespace": "doc_tabs_typical", "layout": { "tabs:main": { "value": "overview", "tabs": [ { "value": "overview", "label": "Overview" }, { "value": "settings", "label": "Settings" } ] } } } ``` ## Usage Notes - Use for settings panel sections, content category switching, and configuration groups. - Not suitable for multi-page wizards — use explicit page state and navigation. - Related components: `button` for submit actions, `link` for cross-page navigation. - Use `$value` and `onchange` for controlled switching. ### Orientation variants ```slex { namespace: "doc_tabs_orientation_diff", layout: { "row:orientations": { "column:h": { "text:horiz": { text: "horizontal (default)" }, "tabs:horizontal": { value: "a", orientation: "horizontal", tabs: [ { value: "a", label: "Tab A" }, { value: "b", label: "Tab B" } ] } }, "column:v": { "text:vert": { text: "vertical" }, "tabs:vertical": { value: "a", orientation: "vertical", tabs: [ { value: "a", label: "Tab A" }, { value: "b", label: "Tab B" } ] } } } } } ``` ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `value` | string | No | Yes | | Current active tab value. | | `tabs` | array | No | No | | Tab definitions with value, label, content, icon, and iconOnly. | | `tabs[].icon` | string | No | No | | Icon name shown before a tab trigger label. | | `tabs[].iconOnly` | boolean | No | No | | Show only the tab icon while retaining label as accessible text. | | `orientation` | string: horizontal, vertical | No | No | `"horizontal"` | Tab list orientation. | | `onchange` | write-expression | No | No | | Write expression invoked when the active tab changes. | --- # Text URL: /docs/components/text Raw Markdown: /docs/components/text.md Source: site/content/components/text/en-US.md --- title: "Text" category: Display status: ready order: 20 summary: "Short text output for status, description, and results." --- # Text Output text content for status messages, descriptions, and result display. ```slex { "slex": "0.1", "namespace": "doc_text_typical", "layout": { "text:status": { "text": "System is healthy" } } } ``` ## Usage Notes - Use for status text, short descriptions, label values, and lightweight output. - Not suitable for long paragraphs or structured data (use `table`). - Related components: `stat` for numeric metrics, `badge` for status labels. - Keep text short; use multiple `text` nodes for longer content. - Typically placed inside `row`, `column`, or `card`. ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `text` | string | No | Yes | | Displayed text. | | `content` | string | No | Yes | | Alias for text. | | `label` | string | No | Yes | | Alias for text. | | `variant` | string: default, muted | No | No | `"default"` | Text visual variant. | | `color` | string | No | Yes | | Optional CSS color for controlled previews. | | `size` | string \| number | No | Yes | | Optional font size. Numbers are treated as px. | | `class` | string | No | No | | Additional host-controlled CSS class. | --- # Toast URL: /docs/components/toast Raw Markdown: /docs/components/toast.md Source: site/content/components/toast/en-US.md --- title: "Toast" category: Feedback status: ready order: 20 summary: "Transient notification with semantic type." --- # Toast Inline notification with semantic type and optional icon. ```slex { "slex": "0.1", "namespace": "doc_toast_typical", "layout": { "toast:saved": { "type": "success", "title": "Saved", "icon": "check-circle", "description": "Changes have been written." } } } ``` ## Usage Notes - Use for save confirmations, operation errors, and status change notifications. - Not suitable for messages that require user response or long-term visibility — use an inline form or `callout` instead. - Related components: `callout` for in-page prompt blocks, `badge` for compact status. - Set `duration` for auto-hide behavior; without it, the toast renders as an inline notification card. - Use `type` only for semantic message purpose. ### Type variants ```slex { namespace: "doc_toast_type_diff", layout: { "column:types": { "toast:info": { type: "info", title: "Info", description: "A new update is available." }, "toast:success": { type: "success", title: "Success", description: "Operation completed." }, "toast:warning": { type: "warning", title: "Warning", description: "Review before proceeding." }, "toast:danger": { type: "danger", title: "Error", description: "Something went wrong." } } } } ``` ## API Reference {#api} | Field | Type | Required | Dynamic | Default | Description | |---|---|---|---|---|---| | `title` | string | No | Yes | | Toast title. | | `heading` | string | No | Yes | | Alias for title. | | `label` | string | No | Yes | | Alias for title. | | `icon` | string | No | No | | Icon name shown at the left of the toast. | | `description` | string | No | Yes | | Toast body text. | | `text` | string | No | Yes | | Alias for description. | | `message` | string | No | Yes | | Alias for description. | | `content` | string | No | Yes | | Alias for description. | | `type` | string: info, success, warning, danger | No | No | `"info"` | Semantic notification type. | | `tone` | string: info, success, warning, danger | No | No | `"info"` | Alias for type. | | `duration` | number | No | No | | Auto-hide delay in milliseconds. | | `dismissable` | boolean | No | No | `true` | Show a close button. | | `dismissible` | boolean | No | No | `true` | Alias for dismissable. | | `closeLabel` | string | No | No | `"Close notification"` | Accessible close button label. | | `closeAriaLabel` | string | No | No | | Alias for closeLabel. | --- # Slex Specification URL: /docs/reference/spec Raw Markdown: /docs/reference/spec.md Source: site/content/reference/spec/en-US.md --- title: Slex Specification v0.1 category: Reference status: ready order: 10 summary: "Public Slex expression envelope, component keys, props, directives, lifecycle, and runtime API contract." slexkitRenderMode: component --- # Slex Specification v0.1 Slex expression envelope, component keys, props, directives, lifecycle, and runtime API contract — SlexKit v0's entire public protocol in one place. Canonical reference for implementors, test authors, and host adapter authors. **v0/beta.** The current implementation may evolve, but the protocol version (v0.1) is independent of the SlexKit package version. The same protocol may remain stable across multiple package releases. ## 1. Slex expression envelope The canonical Slex expression is an object. Slex source is the JavaScript object literal string form of that expression: ```ts type SlexExpression = { slex?: "0.1"; namespace: string; g: Record; layout: Record; }; ``` `slex`, `namespace`, `g`, and `layout` are the standard envelope fields. `slex: "0.1"` is an optional protocol marker for humans, agents, and validators; it does not affect namespace identity or state merging. The runtime also accepts a bare component tree as shorthand: if the input has component keys at the top level and does not define `namespace`, `g`, or `layout`, it is normalized to: ```js { namespace: "default", g: {}, layout: } ``` ## 2. Layout key Component keys use the format: ``` ComponentKey = ComponentType ":" Identifier ``` - `ComponentType` maps to a type in the component registry. - `Identifier` may be empty (e.g. `"box:"`). - Named components use `Identifier` for instance state and lifecycle hooks. - Keys without `:` are not rendered as component nodes. Reserved context names: `g`, `std`, `api`, `$event`, `$item`, `$index`, `$key`. ## 3. Props classification ### Static props Passed to the component unchanged: ```js "text:title": { text: "Hello" } ``` ### `$` read-pipes A string value on a `$`-prefixed key (excluding `$if`, `$for`, `$key`) is evaluated as a JavaScript expression. The result is passed under the key with the `$` prefix removed: ```js "text:value": { "$content": "'Count: ' + g.count" } // Resolves to: content = "Count: " ``` ### `on*` write-pipes A string value on an `on*`-prefixed key is executed as a JavaScript statement: ```js "button:add": { onclick: "g.count++" } "input:name": { onchange: "g.name = String($event || '')" } ``` The handler receives `$event` as the event data. ### Structural directives `$if`, `$for`, `$key` are structural directives and are never passed to the component as props. Children of `$if` and `$for` components are treated as the conditional/iterated subtree. ## 4. `g` merge When the same namespace is mounted or ingested again, the new `g` is merged into the existing store: | Value type | Merge behavior | | ------------------- | ------------------------ | | Function | Overwrites the old value | | Array | Replaces entirely | | Plain object | Recursively deep-merges | | Other scalar | Overwrites the old value | | Keys not in new `g` | Preserved from old `g` | The new `layout` always replaces the current layout. Layout is never deep-merged. ## 5. Expression context Expressions can access these variables: | Variable | Type | Scope | | ------------------ | ----------------------------- | ------------------------ | | `g` | Reactive state proxy | Always | | `std` | Pure SlexKit standard library | Always | | Component state | e.g. `slider.value` | Named components | | `api` | Host-injected object | If `api` option provided | | `$event` | Event data | `on*` handlers only | | `$item` | Current array item | `$for` context only | | `$index` | Current array index | `$for` context only | | `$key` | Current item key | `$for` context only | | Named `$for` alias | e.g. `user` for `"card:user"` | `$for` context only | `std` contains deterministic helpers for math, formatting, units, and small statistics. Sensitive capabilities stay under host-injected `api.*` and may require secure runtime policy. Expression evaluation errors are caught and produce a warning with namespace and path information. The last known value is returned as a fallback. ## 6. Component instance state Component registration declares a state mode: ```ts register(type, renderer, { state: "value" | "checked" | "enabled" | "readable" | "none" }); ``` | Mode | Writable | Behavior | | ---------- | ------------------ | ------------------------------------------------------------- | | `value` | `value` | Input component; `value` writable from expressions and events | | `checked` | `checked`, `value` | Checkbox-like boolean component; both synced and writable | | `enabled` | `enabled` | Switch-like boolean component; enabled state is writable | | `readable` | (none) | Readable from expressions; write emits console warning | | `none` | (none) | No instance state exposed | Input components (`value`/`checked`/`enabled` modes) sync `change` events to instance state automatically. Duplicate-named components share one namespace-level state instance. `input` with `type: "engineering"` is a value-mode component with additional parsed fields. `value` remains the raw input string, while `number`, `valid`, `prefix`, `unit`, `normalized`, and optional `error` expose the parsed engineering number. Supported v1 notation includes scientific notation plus SI prefixes (`p`, `n`, `u`, `µ`, `m`, `k`, `K`, `M`, `meg`, `G`, `T`) with an optional unit suffix. Units are captured but not dimension-converted. ## 7. `$if` `$if` controls component existence: ```js "card:panel": { "$if": "g.visible", "text:body": { text: "Visible" } } ``` - **Truthy** -mounts the component and its subtree with enter animation if `$enter` is defined. - **Falsy** -unmounts the component and subtree with leave animation if `$leave` is defined, then fires lifecycle hooks, disposers, and subtree cleanup. ## 8. `$for` `$for` renders a component for each array element: ```js "text:item": { "$for": "g.items", "$key": "id", "$content": "$item.label" } ``` Context variables: `$item`, `$index`, `$key`. Named components inject the current item as a same-name variable. ### `$key` strategy | `$key` value | Behavior | | ------------------------ | ------------------------------------------------------------------------------- | | `"$value"` | Use the primitive item itself | | `"id"` or other property | Read that property from object items | | Omitted | Use `item.id` if available; otherwise fall back to index with a console warning | Primitive arrays should always specify `$key: "$value"`. ### $for phases 1. **Delete** -Remove items whose keys are absent from the new array (with leave animation). 2. **Add/update/reorder** -Create new items for new keys; update retained items' `forCtx` (item reference, index); reorder DOM nodes to match array order. Updated items fire `onUpdate_`. 3. **Trim** -Defensively remove excess children. ## 9. Lifecycle and cleanup Convention hooks on `g`: ``` g.onMount_() -after component is appended to DOM g.onUnmount_() -before component is removed from DOM g.onUpdate_() -after $for item changes (index or item reference) ``` Component implementations can register resource cleanup: ```ts attachComponentDisposer(el, dispose); ``` Component disposal is triggered by normal unmount, `$if` toggle-off, `$for` item removal, root cleanup, and `disposeNamespace()`. ## 10. Public runtime API | Function | Signature | Description | | ----------------------------------- | ------------------------------------------- | -------------------------------------------------------------------- | | `mount` | `(input, container, options?) => Cleanup` | Parse, merge state, render component tree | | `ingest` | `(input) => boolean` | Ingest state-only Slex, no rendering | | `boot` | `(options?) => void` | Enhance static page code blocks | | `disposeNamespace` | `(namespace) => void` | Release namespace roots, store, and cache | | `register` | `(type, renderer, options?) => void` | Register component type | | `getRenderer` | `(type) => ComponentRenderer \| undefined` | Look up a registered renderer | | `getIcon` | `(name, state?) => string` | Resolve a registered or bundled icon synchronously | | `loadIcon` | `(name, state?) => Promise` | Resolve an icon, using Iconify fallback when not bundled | | `registerIcon` | `(name, svg, options?) => void` | Register one global SVG icon for all components with an `icon` field | | `registerIcons` | `(icons, options?) => void` | Register multiple global SVG icons | | `clearRegisteredIcons` | `() => void` | Clear all custom registered icons | | `getRegisteredIcon` | `(name, state?) => string` | Look up only registered icons (no Phosphor fallback) | | `normalizeIconName` | `(name) => string` | Normalize icon name to kebab-case with set prefix | | `resolveIconWeight` | `(state?) => IconWeight` | Resolve icon weight from component state | | `resolveIconifyIcon` | `(name, state?) => {prefix, name}` | Resolve to Iconify-compatible name pair | | `iconifySvgUrl` | `(name, state?) => string` | Build full Iconify API SVG URL | | `configureComponentScope` | `(options) => void` | Configure framework adapter flush | | `attachComponentDisposer` | `(el, dispose) => void` | Bind cleanup to element lifecycle | | `createSecureRuntime` | `(policy, adapter?) => SecureRuntimeHandle` | Create gated runtime instance | | `mountSecureArtifact` | `(input, container, options) => Cleanup` | Mount in secure sandbox | | `createSlexKitMarkdownRuntimeHost` | `(options?) => MarkdownRuntimeHost` | Create Markdown host instance | | `getSlexKitMarkdownRuntimeHost` | `() => MarkdownRuntimeHost` | Get or create global Markdown host | | `installSlexKitMarkdownRuntimeHost` | `(options?) => MarkdownRuntimeHost` | Install and return global Markdown host | | `getSlexKitRuntimeUrl` | `() => string \| undefined` | Get default sandbox runtime URL | | `setSlexKitRuntimeUrl` | `(url) => void` | Set default sandbox runtime URL | | `diagnoseSlexKitSource` | `(source, error) => Diagnostic` | Locate syntax error in source | | `parseSlexSource` | `(source) => ParseResult` | Parse Slex source to object | | `validateSlexSource` | `(source, options?) => ValidationResult` | Parse-first validation with versions, usage, and stable warning codes | | `runSlexConformance` | `(options?) => ConformanceReport` | Run bundled standard conformance fixtures | | `formatSlexKitDiagnostic` | `(diagnostic) => string` | Format diagnostic to readable string | For full runtime behavior, see [Runtime Model](/docs/reference/runtime). ## 11. Error types ### SlexKitSyntaxError Thrown when Slex source parsing fails. Includes a `diagnostic` property with `message`, `line`, `column`, `detail`, and `excerpt`. ### SlexKitRuntimeError Thrown when a runtime operation violates policy or encounters a runtime failure. Has properties: `kind` (`"policy"` | `"network"` | `"timeout"`), `code` (specific error code string), `message`, `elapsedMs`. ## 12. Markdown language handling SlexKit hosts must only process explicit fence language tags: - `slex` Plain JavaScript, JSON, or untagged code blocks must not be scanned or executed. ## 13. Secure runtime types ```ts type SecureRuntimeHandle = { api: SlexKitRuntimeApi; dispose: () => void; }; ``` For full secure runtime types (`HostRuntimePolicy`, `HostRuntimeAdapter`, `SlexKitRuntimeApi`, `SecureFrameOptions`, `SecureMountOptions`, sandbox message types), see the [security runtime contract](/docs/reference/security). ## 14. ToolHost ToolHost bridges AI tool calls to interactive UI that returns structured user input. It is separate from display-oriented `slex` fences. **Public API:** | Function | Signature | Description | |----------|-----------|-------------| | `renderToolCall` | `(call, container) => ToolRenderHandle` | Compile and mount tool UI, return promise | | `registerToolTemplate` | `(name, compiler) => void` | Register a custom tool template compiler | **Result type:** ```ts type ToolResult = | { toolCallId?: string; toolName: string; status: "submitted"; value: Record } | { toolCallId?: string; toolName: string; status: "ignored"; value: null }; ``` **Built-in templates:** `confirm-action`, `choose-options`, `option-list`, `fill-form`. Templates compile to standard Slex expressions using `card:tool` and `submit:actions` components. The `submit:actions` component submits the tool result; it is only used by tool templates, not general display fences. For full template reference, arguments, type definitions, and custom template development, see [ToolHost documentation](/docs/reference/toolhost). ## 15. Icon system SlexKit includes a built-in icon system with Phosphor Icons, a custom registration API, and Iconify fallback support. **Public API (10 functions):** `registerIcon`, `registerIcons`, `clearRegisteredIcons`, `getIcon`, `getRegisteredIcon`, `loadIcon`, `normalizeIconName`, `resolveIconWeight`, `resolveIconifyIcon`, `iconifySvgUrl`. Icons are resolved through a three-tier chain: registered icons → bundled Phosphor (24 icons, 2 weights) → Iconify API fetch (async, `loadIcon` only). Components that accept an `icon` prop automatically display the resolved SVG. For the full API reference, icon list, naming conventions, and custom icon registration, see [Icon system documentation](/docs/reference/icons). ## 16. Non-goals - No public stable compatibility commitment (v0/beta). - Not a pure JSON cross-platform protocol. - No automatic security hardening of arbitrary browser APIs. - No heuristic scanning of code blocks to guess whether to render. - No implicit wrapping of display UI as function calls. --- # Slex Usage Reference URL: /docs/reference/usage Raw Markdown: /docs/reference/usage.md Source: site/content/reference/usage/en-US.md --- title: Slex Usage Reference category: Reference status: ready order: 20 summary: "Slex source structure, props, directives, events, theming, custom components, and ToolHost usage." slexkitRenderMode: component --- # Slex Usage Reference Slex source authoring covers props, directives, events, theming, custom components, and ToolHost. For first-time setup, start with [Getting Started](/docs/guides/quick-start). Protocol compatibility is covered in the [Slex Specification](/docs/reference/spec). ## Installation Most hosts install the root package: ```sh npm install slexkit ``` ```js import { mount } from "slexkit"; import "slexkit/style.css"; ``` Component-free bare runtime: ```sh npm install slexkit @slexkit/runtime ``` ```js import { mount, register } from "@slexkit/runtime"; ``` This entry does not auto-register the official Svelte components. Use the root `slexkit` package, or explicitly import `@slexkit/components-svelte`, when you want the bundled components. For package roles and host-specific install commands, see [Packages](/docs/reference/packages). ## Slex source structure A Slex source is a JavaScript object literal: ```js { slex: "0.1", namespace: "demo", g: { count: 0 }, layout: { "button:add": { text: "Add", onclick: "g.count++" }, "text:value": { "$content": "'Count: ' + g.count" } } } ``` - `slex` - optional Slex protocol marker; use `"0.1"` for the current public protocol. - `namespace` - state domain identifier (defaults to `"default"`). - `g` - reactive state and logic (functions, data). - `layout` - component tree. As a convenience, a bare component tree (keys containing `:`) is normalized to `{ namespace: "default", g: {}, layout: }`. If the bare tree includes `slex: "0.1"`, that marker is preserved while component keys move under `layout`. ## Props ### Static props Passed to the component as-is: ```js "text:title": { text: "Hello World" } ``` ### Dynamic read-pipes (`$`) A string value on a `$`-prefixed key is evaluated as a JavaScript expression. The result replaces the key stripped of the `$` prefix: ```js "text:value": { "$content": "'Count: ' + g.count" } ``` The `$` prefix is removed. The prop passed to the component is `content`. Re-evaluation is triggered automatically when any reactive dependency changes. ### Write-pipes (`on*`) A string value on an `on*`-prefixed key is executed as a JavaScript statement: ```js "button:add": { onclick: "g.count++" } "input:name": { onchange: "g.name = String($event || '')" } ``` The handler receives `$event` as the event data. ### Structural directives `$if`, `$for`, and `$key` are structural directives - they are not passed to the component as props. ## `$if` - conditional rendering Controls whether the component and its subtree are mounted: ```js "card:panel": { "$if": "g.visible", "text:body": { text: "I am visible" } } ``` When the expression is truthy, the component mounts (with enter animation if `$enter` is defined). When falsy, it unmounts (with leave animation if `$leave` is defined, then cleanup). ## `$for` - array iteration Renders a component for each item in an array: ```js "text:item": { "$for": "g.items", "$key": "id", "$content": "$item.label" } ``` Context variables available inside `$for`: `$item` (current item), `$index` (current index), `$key` (item key). Named components also inject the current item as a same-name variable (e.g. `"card:user"` makes `user` available). ### Key strategy `$key` supports: - `"$value"` - use the primitive item itself as key. - `"id"` (or any property name) - read that property from object items. - Omitted - uses `item.id` if available, otherwise falls back to index with a console warning. Primitive array items should always specify `$key: "$value"`. ### $for update algorithm 1. **Delete phase** - remove items whose keys are no longer in the array (with leave animation). 2. **Add/update/reorder phase** - create new items, update retained items' context (index, item reference), and reorder DOM nodes to match the array. 3. **Trim phase** - defensively remove any excess children. When an item's index or item reference changes, `onUpdate_` is called. ## Events Event handlers are defined as `on*` write-pipes. The component's native change/input events are automatically wired to component instance state for writable components: ```js "input:name": { onchange: "g.name = String($event || '')" } ``` The `$event` variable contains the event data. For change events on writable components (`value`, `checked`, or `enabled` mode), the component state is automatically synced before the handler runs. ## Trusted vs secure mode ### Trusted mode (default) Slex source executes in the host page realm. Use for application-generated content, repository-maintained Slex source, or already-reviewed snippets. ```js import { mount } from "slexkit"; mount(script, container, { theme: "host-shadcn" }); ``` ### Secure mode Untrusted or agent-generated Slex source runs in a sandbox iframe with opaque origin. Sensitive capabilities are gated behind host policy: ```js import { mountSecureArtifact } from "slexkit"; mountSecureArtifact(script, container, { policy: {}, frame: { runtimeUrl: "/slexkit.runtime.js" }, }); ``` Use [Secure Runtime Setup](/docs/guides/security-runtime) for deployment steps. The [Security Runtime Contract](/docs/reference/security) covers policy, sandbox behavior, bridge protocol, and fail-closed requirements. ## Theming Theme mode is resolved from the `theme` option: | Value | Behavior | |-------|----------| | `"auto"` | Checks container for known theme classes; falls back to `"uno"` | | `"host-shadcn"` | shadcn/ui compatible | | `"uno"` | Uno/Flowbite compatible | | `"flowbite"` | Flowbite compatible | Direction (`ltr`, `rtl`, `auto`) is resolved from the inherited `dir` attribute or the document element. ```js mount(script, container, { theme: "host-shadcn", dir: "auto" }); ``` ## Custom components Register a component type with a render function: ```ts import { register } from "slexkit"; register("custom", (props, name, ctx) => { const el = ctx.document.createElement("div"); el.textContent = String(props.label ?? name); return el; }, { state: "value" }); ``` The `RenderContext` provides: | Property | Type | Description | |----------|------|-------------| | `g` | reactive proxy | Global state | | `std` | `SlexKitStdlib` | Pure deterministic helpers | | `api` | `Record` | Host-injected capabilities | | `dir` | `"ltr"` or `"rtl"` | Resolved direction | | `labels` | `Partial>` | Runtime labels | | `id` | `string \| null` | Component name | | `emit` | `(event, data?) => void` | Event emitter | | `children` | `Record` | Nested component tree | | `document` | `Document` | Owner document | | `renderTree` | function | Recursive render helper | Use `attachComponentDisposer(el, fn)` to bind cleanup to the component's DOM lifecycle. ## ToolHost ToolHost handles UI that must return structured user input (confirmations, selections, forms). It is separate from display-oriented `slex` fences. Built-in templates: - `confirm-action` - yes/no confirmation - `choose-options` - single or multi-select - `option-list` - scrollable option list - `fill-form` - structured form with submit Templates compile to standard Slex source. The `submit` component submits the result; only tool templates use it, not display fences. --- # Runtime Model URL: /docs/reference/runtime Raw Markdown: /docs/reference/runtime.md Source: site/content/reference/runtime/en-US.md --- title: Runtime Model category: Reference status: ready order: 30 summary: "Mounting, ingestion, boot, namespace store, lifecycle hooks, component state, and runtime APIs." slexkitRenderMode: component --- # Runtime Model The core SlexKit runtime: entry points, namespace store, component state, lifecycle hooks, and expression evaluation. Slex source syntax is covered in the [protocol specification](/docs/reference/spec). Secure mode isolation is covered in the [security runtime contract](/docs/reference/security). ## Entry points ### `mount(input, container, options)` Parses Slex source object or source string, merges state into the namespace store, renders the component tree into `container`, returns a root cleanup function. ```ts function mount( input: SlexExpression | string, container: HTMLElement, options?: MountOptions ): () => void; type MountOptions = { theme?: "auto" | "host-shadcn" | "uno" | "flowbite"; dir?: "ltr" | "rtl" | "auto"; labels?: Partial>; api?: Record; }; ``` Calling `mount()` again on the same `container` clears the old root first, then appends a new root. The returned cleanup only unmounts the current root; it does not delete the namespace store. Every expression receives `std`, SlexKit's pure deterministic standard library. Hosts can still inject capability objects through `api`, but network, timers, animation, and canvas should remain policy-gated in secure mode. ### `ingest(input)` Ingests state-only Slex: updates `g` without rendering UI. Used by the Markdown runtime host for state-only fences. Returns `true` if parsing succeeded. ```ts function ingest(input: SlexExpression | string): boolean; ``` ### `disposeNamespace(namespace)` Permanently releases all roots, cleanups, store entries, and expression caches for a namespace. Call this when a document, message domain, or page section is permanently removed. Root cleanup is not equivalent to namespace disposal. ```ts function disposeNamespace(namespace: string): void; ``` ### `boot(options)` Enhances static pages by auto-discovering explicitly marked Slex blocks (`
`) and mounting live previews.

```ts
function boot(options?: BootOptions): void;

type BootOptions = {
  selector?: string;
  sourceControls?: boolean;
  theme?: ThemeMode;
  dir?: MountOptions["dir"];
  labels?: MountOptions["labels"];
};
```

Default selector covers: `language-slex`.

Hosts like React/Streamdown or Obsidian should typically use the Markdown runtime host directly rather than `boot()`.

### `register(type, renderer, options)`

Registers a component type with a render function and state mode.

```ts
function register(
  type: string,
  renderer: ComponentRenderer,
  options?: ComponentRegistrationOptions
): void;

type ComponentRenderer = (
  props: Record,
  name: string,
  ctx: RenderContext
) => HTMLElement | void;

type ComponentRegistrationOptions = {
  state?: "value" | "checked" | "enabled" | "readable" | "none";
};
```

### `configureComponentScope(options)`

Configures a flush function for component scope. Framework adapters use it to synchronize DOM after reactive updates.

```ts
function configureComponentScope(options: { flush?: () => void }): void;
```

## Validation and conformance

### `validateSlexSource(source, options)`

Validates Slex source after parsing. The result includes `schemaVersion`, `protocolVersion`, `logicProfileVersion`, usage lists, and warning codes. Syntax failures return a diagnostic.

```ts
function validateSlexSource(
  source: string,
  options?: { mode?: "trusted" | "secure" }
): ValidationResult;
```

### `runSlexConformance(options)`

Runs the bundled standard fixtures against the current validator. Pass `fixtureId` to run one fixture.

```ts
function runSlexConformance(options?: { fixtureId?: string }): ConformanceReport;
```

## Namespace store

`namespace` is the state domain. Multiple mounts with the same namespace share one store:

- New `g` is deep-merged into the old `g` (functions overwrite, objects recursively merge, arrays replace, scalars overwrite).
- New `layout` replaces the current layout (no deep merge for layout).
- Component instance state is persisted within the namespace.
- Expression caches are managed per namespace.

This allows a document, message domain, or tool panel to update its UI incrementally while preserving state.

## Component instance state

Named components can expose instance state. Which prop is writable depends on the component's registered state mode:

| Mode | Writable prop | Behavior |
|------|---------------|----------|
| `value` | `value` | Writable from expressions and events |
| `checked` | `checked`, `value` | Both synced, writable |
| `enabled` | `enabled` | Switch enabled state, writable |
| `readable` | (none) | Readable from expressions, write emits a console warning |
| `none` | (none) | No state exposed |

```js
{
  layout: {
    "slider:threshold": { value: 42 },
    "text:preview": { "$content": "'Threshold: ' + threshold.value" }
  }
}
```

Repeatedly named components share namespace-level state. `$for` items with the same component name also share one state instance.

## Lifecycle hooks

The runtime calls convention-based hooks on the `g` object:

```
g.onMount_()      // after component is appended to DOM
g.onUnmount_()    // before component is removed from DOM
g.onUpdate_()     // after $for item index or item reference changes
```

These hooks fire for normal components, `$if` branches, and `$for` slots. Root cleanup and `disposeNamespace()` trigger `onUnmount`.

## Component disposer

Framework components, event listeners, subscriptions, and external resources should bind their cleanup to the component DOM element:

```ts
import { register, attachComponentDisposer } from "slexkit/runtime";

register("custom", (props, name, ctx) => {
  const el = ctx.document.createElement("div");
  const stop = subscribeSomething();
  attachComponentDisposer(el, stop);
  return el;
});
```

The runtime calls the disposer when the element is unmounted. The official Svelte adapter uses this mechanism to destroy Svelte component instances.

## Expression evaluation context

Expressions in `$` read-pipes and statements in `on*` write-pipes can access these variables:

| Variable | Type | Availability |
|----------|------|--------------|
| `g` | reactive state proxy | always |
| `api` | host-injected capabilities | if `api` option passed to `mount()` |
| `$event` | event data | `on*` handlers only |
| `$item` | current array item | `$for` context only |
| `$index` | current array index | `$for` context only |
| `$key` | current item key | `$for` context only |
| named component state | e.g. `threshold.value` | named components |

Expression evaluation uses `new Function()` in trusted mode. Evaluation errors are caught and produce a console warning with namespace and path information; the last known value is used as a fallback.

---

# Host Integration

URL: /docs/reference/integration
Raw Markdown: /docs/reference/integration.md
Source: site/content/reference/integration/en-US.md

---
title: Host Integration
category: Reference
status: ready
order: 40
summary: "MarkdownRuntimeHost, trusted and secure host integrations, Svelte custom hosts, Streamdown, Tiptap, Obsidian, and custom adapters."
slexkitRenderMode: component
---

# Host Integration

How to integrate SlexKit into Markdown renderers, chat hosts, document viewers, and custom platforms.

## Core concepts

### Artifact

An artifact is a group of Slex blocks belonging to the same document, message, or note. Hosts identify an artifact by an `artifactId` and group related blocks into one runtime domain.

In **trusted mode**, the runtime prefixes each block's namespace with the artifact ID to prevent cross-document state pollution. `disposeArtifact()` releases all namespace stores for that artifact.

In **secure mode**, all fences in one artifact are combined into a single sandbox iframe. The runtime uses artifact slots to sync rendered heights back to the original Markdown placeholder containers.

### Block

A block is a single Slex block: one renderable unit. It has:
- A source (Slex expression object or source string).
- A container element (where the rendered output goes).
- An optional `artifactId` (for grouping into an artifact).

### Cleanup

Every block mount returns a cleanup function. The host must call it when the block is removed. For artifact-level cleanup, call `disposeArtifact(artifactId)`. For global cleanup, call `disposeAll()`.

## MarkdownRuntimeHost

The `SlexKitMarkdownRuntimeHost` is the recommended API for Markdown-based hosts. It handles mode selection, artifact management, and block lifecycle.

```ts
import {
  createSlexKitMarkdownRuntimeHost,
  getSlexKitMarkdownRuntimeHost,
  installSlexKitMarkdownRuntimeHost
} from "slexkit";
```

### Interface

```ts
type SlexKitMarkdownRuntimeHost = {
  configure(options: Partial): void;
  getMode(): "trusted" | "secure";
  mountBlock(block: SlexKitMarkdownBlock): () => void;
  disposeBlock(container: HTMLElement): void;
  disposeArtifact(artifactId: string): void;
  disposeAll(): void;
};

type SlexKitMarkdownBlock = {
  artifactId?: string;
  blockId?: string;
  source: SlexExpression | string;
  container: HTMLElement;
  stateOnly?: boolean;
  theme?: ThemeMode;
  dir?: MountOptions["dir"];
  labels?: MountOptions["labels"];
  executionMode?: MountOptions["executionMode"];
};

type SlexKitMarkdownRuntimeOptions = {
  mode?: "trusted" | "secure";
  policy?: HostRuntimePolicy;
  hostAdapter?: HostRuntimeAdapter;
  secureFrame?: boolean | SecureFrameOptions;
  theme?: ThemeMode;
  dir?: MountOptions["dir"];
  labels?: MountOptions["labels"];
  executionMode?: MountOptions["executionMode"];
};
```

`executionMode: "preview"` is for speculative renders of repaired streaming prefixes. In preview mode, trusted mounts render readable UI but freeze write handlers, component emits, lifecycle hooks, and `api.*` capabilities. Blocks can override a host-level default by passing `executionMode` directly to `mountBlock()`.

### Global singleton

The module provides a global singleton for convenience:

```ts
// Install explicitly
const runtime = installSlexKitMarkdownRuntimeHost({
  mode: "secure",
  policy: { execution: { maxUnresponsiveMs: 30000 } },
  secureFrame: { runtimeUrl: "/slexkit.runtime.js" }
});

// Or use lazy global (auto-creates with defaults on first call)
const runtime = getSlexKitMarkdownRuntimeHost();
```

Use the singleton when the entire application shares one runtime configuration. Avoid it when different host contexts need different policies.

## Trusted mode integration

Trusted mode runs Slex source in the host page realm. Use for local documents, application-generated content, or reviewed Slex source.

```ts
const runtime = createSlexKitMarkdownRuntimeHost({
  mode: "trusted",
  theme: "host-shadcn"
});

// Detect a slex fence at position 
const cleanup = runtime.mountBlock({
  artifactId: "doc-1",
  source: fenceSource,
  container: fenceContainer
});

// When the fence container is removed
runtime.disposeBlock(fenceContainer);

// When the document is closed
runtime.disposeArtifact("doc-1");

// When the plugin or page unloads
runtime.disposeAll();
```

In trusted mode, the runtime automatically scopes namespaces by artifact ID (`::`) to prevent different documents from polluting each other's state.

State-only blocks (no `layout`, only `g` updates) are detected automatically and ingested via `ingest()`. Subsequent renderable blocks in the same artifact can read that state.

## Secure mode integration

Secure mode runs Slex source in a sandbox iframe. Use for untrusted or agent-generated Markdown.

```ts
const runtime = createSlexKitMarkdownRuntimeHost({
  mode: "secure",
  policy: {
    execution: { maxUnresponsiveMs: 30000 }
  },
  secureFrame: {
    runtimeUrl: "/slexkit.runtime.js"
  },
  theme: "host-shadcn"
});

const cleanup = runtime.mountBlock({
  artifactId: "agent-msg-1",
  source: agentGeneratedDsl,
  container: fenceContainer
});
```

Omitted capability policies deny access by default. Add `network`, `timer`, `animation`, or `canvas` policy objects only when the host intentionally enables those capabilities.

### Artifact slot bridge

When multiple secure blocks belong to the same artifact, they share one sandbox iframe. The first block (in document order) becomes the iframe anchor. Other blocks act as slots; their containers receive position and height updates from the sandbox via the postMessage bridge.

```html

``` This allows state sharing across fences within one artifact while keeping all execution confined to one sandbox. ### `runtimeUrl` requirements The `runtimeUrl` must serve the SlexKit runtime as an ES module with: ``` Access-Control-Allow-Origin: * Content-Type: text/javascript ``` The build output includes `dist/runtime.js` for this purpose. The `slex copy-runtime` command copies that module to `public/slexkit.runtime.js` by default so existing secure-frame URLs can stay stable. Configure the CDN or static file server to serve it with the correct headers. ## Svelte custom Markdown host The SlexKit website uses Svelte plus a custom Markdown renderer instead of a packaged Svelte Markdown adapter. The public contract is still `createSlexKitMarkdownRuntimeHost`; the Svelte pieces are host code. ```js import { mount, unmount } from "svelte"; import { createSlexKitMarkdownRuntimeHost } from "slexkit"; import MarkdownRenderer from "./MarkdownRenderer.svelte"; export function renderMarkdown(content, container, options = {}) { const runtimeHost = options.slexkitRuntimeHost ?? createSlexKitMarkdownRuntimeHost({ mode: options.runtimeMode ?? "trusted", theme: "host-shadcn" }); const app = mount(MarkdownRenderer, { target: container, props: { content, runtimeHost, artifactId: options.artifactId, slexkitRenderMode: options.slexkitRenderMode ?? "component" } }); return () => unmount(app); } ``` Use this as an implementation reference when the host owns its Markdown AST or Svelte renderer. Do not treat `site/markdown/*` as a separately versioned package API. ## Streamdown / React integration The `@slexkit/streamdown` package provides a React/Streamdown custom renderer: ```tsx import { Streamdown } from "streamdown"; import { slexkitRenderer } from "@slexkit/streamdown"; import "@slexkit/theme-shadcn/style.css"; import "@slexkit/streamdown/style.css"; export function Message({ markdown }: { markdown: string }) { return ( {markdown} ); } ``` The renderer handles `slex` fences. It supports both trusted and secure runtime modes and can delegate to a shared Markdown runtime host instance. During token streaming, `streaming="repair"` is the default for trusted renders. A parseable source mounts immediately; a source missing only EOF closing tokens mounts as preview; uncertain prefixes stay on the placeholder; clear syntax errors still render diagnostics. Use `streaming="stable"` to render only already-parseable prefixes, or `streaming={false}` to wait for the closing fence. Secure runtime and secure runtime-host renders do not execute repaired prefixes in the host realm. ## Tiptap integration The `@slexkit/tiptap` package provides a framework-free Tiptap `CodeBlock` extension: ```ts import StarterKit from "@tiptap/starter-kit"; import { Markdown } from "@tiptap/markdown"; import { createSlexKitTiptapExtension } from "@slexkit/tiptap"; import "@slexkit/theme-shadcn/style.css"; import "@slexkit/tiptap/style.css"; const extensions = [ StarterKit.configure({ codeBlock: false }), Markdown, createSlexKitTiptapExtension({ artifactId: "doc-1" }) ]; ``` The adapter only takes over `codeBlock` nodes with `language === "slex"`. Non-Slex code blocks remain ordinary Tiptap code blocks, and Markdown import/export keeps standard ` ```slex ` fences through Tiptap's Markdown extension. Each editor instance gets one trusted Markdown runtime host by default. Blocks in that editor share an artifact ID, so state-only fences can seed later renderable fences. Pass `runtimeHost` or `artifactId` when the host needs explicit lifecycle ownership. ## Obsidian integration The official Obsidian plugin is available at and registers the `slex` fenced code block processor: ```ts // In the plugin: registerMarkdownCodeBlockProcessor("slex", (source, el, ctx) => { ... }); ``` The adapter renders blocks in **reading mode only** and does not write back to the vault. Blocks within the same note share a trusted artifact runtime. **Important**: The Obsidian adapter uses trusted mode because it renders content from the user's local vault. It is not designed as a security boundary for untrusted or agent-generated Markdown. ## Writing a custom host adapter To integrate SlexKit into a custom Markdown renderer or chat host: ### 1. Detect fence language Only process fences tagged with `slex`. Never scan plain JavaScript, JSON, or untagged code blocks. ### 2. Create a runtime host ```ts import { createSlexKitMarkdownRuntimeHost } from "slexkit"; const runtime = createSlexKitMarkdownRuntimeHost({ mode: "trusted", // or "secure" theme: "host-shadcn" }); ``` ### 3. Mount blocks For each detected fence, create a container element and mount: ```ts function processFence(source: string, fenceIndex: number) { const container = document.createElement("div"); // Insert container at the fence position in the document const cleanup = runtime.mountBlock({ artifactId: "message-42", source, container }); return cleanup; } ``` ### 4. Manage lifecycle ```ts // When a single block is removed runtime.disposeBlock(container); // When the entire artifact (message/document) is removed runtime.disposeArtifact("message-42"); // When the plugin/page unloads runtime.disposeAll(); ``` ### 5. Handle secure mode If using secure mode, serve `slexkit.runtime.js` as a public ES module with the correct CORS headers, and configure `secureFrame.runtimeUrl`. ## Fallback rendering SlexKit-capable hosts should still include the raw fence content or a plain text fallback in the DOM for environments that don't support SlexKit. The runtime replaces the container children, so fallback text is only visible before mount or after disposal. --- # Security Runtime URL: /docs/reference/security Raw Markdown: /docs/reference/security.md Source: site/content/reference/security/en-US.md --- title: Security Runtime Contract category: Reference status: ready order: 50 summary: "Threat model, sandbox iframe deployment, host policy, postMessage bridge, and fail-closed behavior." slexkitRenderMode: component --- # Security Runtime Contract The secure runtime defines what untrusted Slex source can and cannot do, how the host authorizes capabilities, and how sandbox isolation works. ## Threat model - The host page and host application are trusted. - Slex source may be untrusted. - Secure artifacts run inside a sandbox iframe. - The iframe uses an opaque origin by default (no `allow-same-origin`). - Slex source must not access the host DOM, cookies, `localStorage`, `IndexedDB`, or host global objects. Secure mode confines expression execution to an isolated environment and consolidates sensitive capabilities under the host `policy` and `api.*`. ## Authorization source The sole authorization source is the `HostRuntimePolicy` provided by the host. Slex source fields such as `capabilities`, `permissions`, `api`, or other top-level declarations cannot grant themselves authority. All capabilities are accessed through `api.*`: ``` api.get(url, options) api.post(url, body, options) api.fetch(url, options) api.setTimeout(fn, ms) api.clearTimeout(id) api.setInterval(fn, ms) api.clearInterval(id) api.raf(fn) api.cancelRaf(id) api.createCanvas(width, height) api.getCanvasContext(canvas, contextId, options) api.onDispose(fn) api.now() api.isTimeoutError(error) api.isNetworkError(error) api.isPolicyError(error) api.errorMessage(error) ``` Capabilities not exposed through `api.*` are unsupported. ## HostRuntimePolicy ```ts type HostRuntimePolicy = { network?: { enabled: boolean; methods: ("GET" | "POST")[]; allowOrigins: string[]; allowHeaders?: string[]; allowContentTypes?: string[]; credentials: "omit" | "same-origin" | "include"; timeoutMs: number; maxBodyBytes: number; maxResponseBytes?: number; }; timer?: { enabled: boolean; maxTimers: number; minIntervalMs: number; }; animation?: { enabled: boolean; }; canvas?: { enabled: boolean; maxCanvases?: number; maxPixels?: number; allowedContexts?: ("2d" | "webgl" | "webgl2" | "bitmaprenderer")[]; }; execution?: { heartbeatIntervalMs?: number; maxUnresponsiveMs?: number; }; }; ``` ### Network policy Network is denied by default unless `policy.network.enabled` is `true`. The policy constrains: - HTTP method (only listed methods allowed) - Origin (supports `*`, exact match, `protocol://*` protocol wildcard, and `protocol://*.domain` subdomain wildcard) - Request headers (only listed headers pass; `Authorization`, `Cookie`, `Proxy-Authorization`, `Set-Cookie`, and Sec-Fetch headers are always blocked) - Credentials mode - Request body size - Request timeout - Response body size - Response content-type `hostAdapter.fetch` can replace the actual request implementation. `hostAdapter.onNetworkLog` is observational only; it must not alter runtime behavior. ### Timer, animation, and canvas - **Timer**: denied by default. When enabled, subject to `maxTimers` (total concurrent) and `minIntervalMs` (minimum delay). All timers and intervals are cleaned up on dispose. - **Animation**: denied by default. Controlled via `animation.enabled`; `api.raf` is the only animation primitive. - **Canvas**: denied by default. When enabled, subject to `maxCanvases`, `maxPixels`, and `allowedContexts`. ### Execution monitoring `execution.heartbeatIntervalMs` controls how often the sandbox sends a heartbeat to the host. `execution.maxUnresponsiveMs` defines the maximum silence before the sandbox is terminated as unresponsive. ## HostRuntimeAdapter The adapter allows the host to override or observe runtime behavior: ```ts type HostRuntimeAdapter = { fetch?: (request: HostFetchRequest) => Promise; onNetworkLog?: (event: RuntimeNetworkLogEvent) => void; onRuntimeError?: (event: RuntimeErrorEvent) => void; now?: () => number; setTimeout?: (fn: () => void, ms: number) => TimerId; clearTimeout?: (id: TimerId) => void; setInterval?: (fn: () => void, ms: number) => TimerId; clearInterval?: (id: TimerId) => void; requestAnimationFrame?: (fn: (time: number) => void) => RafId; cancelAnimationFrame?: (id: RafId) => void; }; ``` `onNetworkLog` and `onRuntimeError` are audit hooks; they must not change runtime behavior. Errors thrown within them are silently caught. ## Sandbox iframe deployment The secure frame imports the main runtime module from a `runtimeUrl`: ```ts mountSecureArtifact(script, container, { frame: { runtimeUrl: "/slexkit.runtime.js" } }); ``` This URL must serve as a public ES module and return: ``` Access-Control-Allow-Origin: * Content-Type: text/javascript ``` This is server or deployment layer configuration; it cannot be set from frontend JavaScript. ### CSP The sandbox iframe is served via `srcdoc` with a strict Content-Security-Policy: ``` default-src 'none' script-src 'nonce-{random}' 'unsafe-eval' {runtimeOrigin} connect-src 'none' img-src data: blob: style-src 'unsafe-inline' font-src data: form-action 'none' base-uri 'none' ``` A random nonce is generated for each frame instance. `unsafe-eval` is required because Slex source expression evaluation uses `eval()` inside the sandbox. ### Sandbox attribute The iframe requires `allow-scripts`. `allow-same-origin` is **blocked by default** because it would weaken the opaque origin isolation. Only set `unsafeAllowSameOrigin: true` explicitly if the host accepts the risk: ```ts frame: { unsafeAllowSameOrigin: true, // only with explicit host acceptance sandbox: "allow-scripts allow-same-origin" } ``` Do not add `allow-same-origin` to fix CORS or debugging issues. ## postMessage bridge protocol The host and sandbox communicate via `window.postMessage`. All messages are tagged with `channel: "slexkit-secure"`. ### Host -Sandbox messages | Type | Purpose | |------|---------| | `mount` | Sends Slex source, policy, theme to render | | `dispose` | Tells sandbox to tear down | | `fetch-result` | Returns fetch response or error | | `slots` | Synchronizes artifact slot positions | ### Sandbox -Host messages | Type | Purpose | |------|---------| | `ready` | Runner module loaded and listening | | `mounted` | Artifact render confirmed | | `disposed` | Sandbox teardown acknowledged | | `heartbeat` | Periodic liveness signal | | `error` | Mount or runtime error | | `fetch` | Proxied network request | | `slot-size` | Artifact slot height report | Every host→sandbox message includes an `id` and `token`. The token is opaque, cryptographically random, and scoped to a single mount instance. Messages with mismatched tokens are rejected. Messages are verified: the sandbox checks `event.source === window.parent`; the host checks `event.source === iframe.contentWindow`. ## Artifact slot bridge Multiple Markdown fences belonging to one artifact share a single sandbox iframe. The host sends slot rectangles to the sandbox, which renders each fence's output inside the corresponding slot container. The sandbox reports each slot's rendered height back via `slot-size` messages. A `ResizeObserver` on the host side and inside the sandbox keeps positions and heights synchronized. This preserves visual continuity across fences while keeping all execution confined to one isolation context. ## Heartbeat watchdog When `execution.maxUnresponsiveMs` is set, the host monitors the sandbox heartbeat interval. If no heartbeat arrives within the threshold, the iframe is terminated, a diagnostic alert (`role="alert"`) is rendered, and a `console.error` is emitted. ## Fail-closed behavior If the iframe cannot load the runtime, does not send a ready/mounted message, or the heartbeat times out, SlexKit: 1. Removes the unresponsive iframe. 2. Renders a `role="alert"` diagnostic element with a description of the failure. 3. Emits the same information via `console.error`. Load timeout is configurable via `frame.loadTimeoutMs` (default: 8000ms). ## Escape hatches ### `unsafeInlineExecution` Allows a secure artifact to execute inline in the host page with an injected secure runtime API. **Intended for testing or host-trusted content only.** Not recommended for untrusted paths. ```ts mountSecureArtifact(script, container, { policy, hostAdapter, unsafeInlineExecution: true }); ``` ### `unsafeAllowSameOrigin` Allows `allow-same-origin` in the sandbox attribute. **Reduces isolation strength**; only use when the host explicitly accepts the risk. ```ts frame: { sandbox: "allow-scripts allow-same-origin", unsafeAllowSameOrigin: true } ``` ## Sandbox hardening When the sandbox runner starts, it hardens the global scope: **Blocked network globals** -`fetch`, `XMLHttpRequest`, `WebSocket`, `EventSource`, `Worker`, `SharedWorker`, and `navigator.sendBeacon` are replaced with functions that throw, ensuring all network traffic must go through the bridge. **Blocked scheduling globals** -`setTimeout`, `setInterval`, `requestAnimationFrame` are replaced with functions that throw, directing code to `api.setTimeout()`, `api.setInterval()`, and `api.raf()`. **Canvas prototype wrapping** -`HTMLCanvasElement.prototype.getContext` is wrapped to enforce canvas policy on context creation. `OffscreenCanvas` is replaced with a subclass that validates dimensions on construction. ## Maintenance principles - New capabilities must define a policy field first, then an `api.*` method, then the bridge. - Slex source declarations are never an authorization source. - Default to opaque origin. - Always fail closed. - Log and error hooks are observational; they must not alter runtime behavior. --- # Packages URL: /docs/reference/packages Raw Markdown: /docs/reference/packages.md Source: site/content/reference/packages/en-US.md --- title: Packages category: Reference status: ready order: 60 summary: "SlexKit npm package roles, install combinations, publish contents, and release checks." slexkitRenderMode: component --- # Packages SlexKit v0/beta package references list npm packages, install commands, and release checks. ## Package Map ``` slexkit (root package) ├── runtime entry ├── Svelte component registrations ├── ToolHost ├── default styles └── secure iframe runner @slexkit/runtime ─── re-exports slexkit/runtime @slexkit/components-svelte ─── re-exports slexkit/components-svelte @slexkit/theme-shadcn ─── CSS only @slexkit/streamdown ─── React/Streamdown renderer @slexkit/assistant-ui ─── assistant-ui Streamdown text wrapper @slexkit/tiptap ─── framework-free Tiptap NodeView adapter @slexkit/mcp ─── read-only MCP server for AI agents ``` `@slexkit/runtime` and `@slexkit/components-svelte` are published npm packages, but their code wraps the root `slexkit` package. They are not independent implementation packages; installing them still requires installing `slexkit`. `@slexkit/theme-shadcn` is CSS-only and contains no runtime implementation. ## slexkit (root) The main implementation package. It contains the runtime engine, official Svelte components, ToolHost, and styles. ```sh npm install slexkit ``` ```js import { mount, disposeNamespace, boot } from "slexkit"; import "slexkit/style.css"; // default styles (includes all component CSS) ``` `slexkit/dist/style.css` is a compatibility alias for the same distributed CSS bundle; do not import both paths. Version helpers are exported from both the root and runtime entries: ```js import { SLEXKIT_VERSION, SLEX_PROTOCOL_VERSION, getSlexKitInfo } from "slexkit"; ``` The root package also ships the `slex` CLI: ```sh slex copy-runtime public/slexkit.runtime.js slex validate ./artifact.slex --mode secure slex validate --standard ``` `slex validate --standard` runs the bundled Slex conformance fixtures against the validator shipped with the package. Use `--json` for CI or agent consumption. ## @slexkit/runtime Component-free runtime entry point. Does not auto-register any official Svelte components. ```sh npm install slexkit @slexkit/runtime ``` ```js import { mount, register, createSecureRuntime } from "@slexkit/runtime"; ``` Use this to register a custom component set instead of the bundled Svelte components. ## @slexkit/components-svelte Side-effect import that registers all official Svelte components into the runtime registry. ```sh npm install slexkit @slexkit/runtime @slexkit/components-svelte ``` ```js import { mount } from "@slexkit/runtime"; import "@slexkit/components-svelte"; ``` Public component specs: action (1), component (1), content (6), data (1), disclosure (2), display (3), feedback (2), input (6), layout (4), navigation (1), tooling (3). ## @slexkit/theme-shadcn CSS theme bundle (shadcn/ui compatible). ```sh npm install @slexkit/theme-shadcn ``` ```js import "@slexkit/theme-shadcn/style.css"; ``` ## @slexkit/streamdown React/Streamdown custom renderer for Markdown-hosted SlexKit fences. ```sh npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown streamdown react react-dom ``` ```tsx import { Streamdown } from "streamdown"; import { slexkitRenderer } from "@slexkit/streamdown"; import "@slexkit/theme-shadcn/style.css"; import "@slexkit/streamdown/style.css"; export function Message({ markdown }: { markdown: string }) { return ( {markdown} ); } ``` Processes `slex` fences. Supports both trusted and secure runtime modes. ## @slexkit/assistant-ui assistant-ui message text wrapper for SlexKit fences. It delegates Markdown rendering to `@assistant-ui/react-streamdown` and only overrides the `slex` language block with `@slexkit/streamdown`. ```sh npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown @slexkit/assistant-ui @assistant-ui/react @assistant-ui/react-streamdown streamdown react react-dom ``` ```tsx import { MessagePrimitive } from "@assistant-ui/react"; import { SlexKitAssistantStreamdownText } from "@slexkit/assistant-ui"; import "@slexkit/theme-shadcn/style.css"; import "@slexkit/assistant-ui/style.css"; export function AssistantMessage() { return ( {({ part }) => part.type === "text" ? ( ) : null } ); } ``` The runtime defaults to secure. assistant-ui tool calls and ToolHost flows still use their own integration layers. ## @slexkit/tiptap Tiptap extension for rendering explicit `slex` code blocks as SlexKit previews while preserving normal fenced code block Markdown roundtrip. ```sh npm install slexkit @slexkit/theme-shadcn @slexkit/tiptap @tiptap/core @tiptap/pm @tiptap/starter-kit @tiptap/extension-code-block @tiptap/markdown ``` ```ts import StarterKit from "@tiptap/starter-kit"; import { createSlexKitTiptapExtension } from "@slexkit/tiptap"; import "@slexkit/theme-shadcn/style.css"; import "@slexkit/tiptap/style.css"; const extensions = [ StarterKit.configure({ codeBlock: false }), createSlexKitTiptapExtension({ artifactId: "doc-1" }) ]; ``` The extension only takes over code blocks whose language is `slex`; ordinary code blocks stay native to Tiptap. It uses a trusted Markdown runtime host unless configured otherwise. Add `@tiptap/markdown` when loading or exporting Markdown. ## Obsidian plugin The official Obsidian plugin lives in a separate release repository: . Install **SlexKit** through Obsidian Community Plugins for normal vault use. Use BRAT or manual GitHub release assets only when testing unreleased builds from `slexkit/obsidian-slexkit`. The community plugin is marked desktop-only and compatible with Obsidian 1.5.0+. The plugin treats the user's local vault as trusted and uses trusted runtime mode. Do not use it as a sandbox for third-party or agent-generated Markdown; the v0 adapter does not include secure sandbox support. ## @slexkit/mcp Read-only MCP server for AI agents. It serves generated LLM docs, component metadata, examples, runtime docs, ToolHost docs, and Slex source validation. ```sh npx -y @slexkit/mcp ``` The server does not modify project files. Use it when an agent needs SlexKit component or runtime context. ## Installation matrix | Use case | Install command | |----------|----------------| | Quick start, everything included | `npm install slexkit` | | Component-free, custom components | `npm install slexkit @slexkit/runtime` | | With Svelte components | `npm install slexkit @slexkit/runtime @slexkit/components-svelte` | | Add shadcn theme | `npm install @slexkit/theme-shadcn` | | React/Streamdown host | `npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown streamdown react react-dom` | | assistant-ui host | `npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown @slexkit/assistant-ui @assistant-ui/react @assistant-ui/react-streamdown streamdown react react-dom` | | Tiptap editor host | `npm install slexkit @slexkit/theme-shadcn @slexkit/tiptap @tiptap/core @tiptap/pm @tiptap/starter-kit @tiptap/extension-code-block @tiptap/markdown` | | Obsidian plugin | Install **SlexKit** from Obsidian Community Plugins | | AI agent MCP server | `npx -y @slexkit/mcp` | ## v0 Package Layout In v0, the root `slexkit` package carries the main implementation. Scoped `@slexkit/*` packages provide clearer install entry points. If these become physical packages later, source code, build output, and publish workflows need to split together. ## Release Check Check all scoped packages together before publishing: ```sh bun run build bun run test bun run lint bun run smoke:release npm pack --dry-run --json slex validate --standard --json ``` The release smoke packs and installs every scoped package in this repository, verifies public entry points, verifies CSS subpath exports, runs the installed `slex validate --standard --json`, and starts the MCP stdio binary to check `initialize`, `tools/list`, and `slexkitValidate`. Before publishing, check that `npm pack --dry-run --json` includes `dist/standard/*` and `scripts/cli.mjs`. Standard artifacts must match `package.json`, `SLEX_PROTOCOL_VERSION`, and the bundled conformance fixtures. --- # Slex Standard Artifacts URL: /docs/reference/standard Raw Markdown: /docs/reference/standard.md Source: site/content/reference/standard/en-US.md --- title: Slex Standard Artifacts category: Reference status: ready order: 65 summary: "JSON artifacts for the Slex envelope, component catalog, logic profile, capabilities, conformance fixtures, and manifest." slexkitRenderMode: component --- # Slex Standard Artifacts SlexKit provides machine-readable JSON files for agents, host runtimes, MCP servers, and package users. These files describe Slex as a Markdown-embedded UI artifact with local state and logic, not as a pure JSON card catalog. The JSON files are generated from the TypeScript runtime registry, component specs, runtime version constants, expression capability metadata, and conformance fixtures. ## Files - [`/standard/slex-standard-manifest.json`](/standard/slex-standard-manifest.json): version, protocol, logic profile, artifact paths, and hashes. - [`/standard/slex-expression.schema.json`](/standard/slex-expression.schema.json): JSON Schema for the Slex envelope, `namespace`, `g`, `layout`, component keys, and directive fields. - [`/standard/slex-component-catalog.json`](/standard/slex-component-catalog.json): public component props, dynamic flags, generated prop JSON Schema, state modes, children, examples, docs, and per-component hashes. - [`/standard/slex-logic-profile.json`](/standard/slex-logic-profile.json): `$` read-pipes, `on*` write-pipes, `$if`, `$for`, `$key`, context variables, reserved names, component state, and secure-mode native capability policy. - [`/standard/slex-capabilities.catalog.json`](/standard/slex-capabilities.catalog.json): deterministic `std.*` functions and policy-gated `api.*` secure runtime capabilities. - [`/standard/slex-conformance.json`](/standard/slex-conformance.json): valid, warning, and invalid fixtures with stable expected diagnostic codes, paths, and values. ## Validation Model Validation is parse-first: 1. Parse the JavaScript object literal source. 2. Validate the Slex envelope and component-key shape. 3. Compare component names and props against the generated component catalog. 4. Scan logic strings and source text against the logic profile. 5. Return stable diagnostic and warning codes. `validateSlexSource()` keeps its previous structured output and adds `schemaVersion`, `protocolVersion`, and `logicProfileVersion`. Secure-mode diagnostics should guide authors toward policy-gated `api.*` capabilities instead of treating all logic as forbidden. Warnings are path-aware after parsing. For example, an unknown `std.*` call in `layout.text:value.$text` and a native `fetch()` call in `g.load` produce different stable paths, so tools can point to one expression instead of rewriting the whole artifact. ## Run Conformance Use the bundled conformance runner to verify that SlexKit's validator still matches the published standard fixtures: ```sh slex validate --standard slex validate --standard --json slex validate --standard --fixture valid-full-envelope ``` Use file validation for a single Slex source: ```sh slex validate ./artifact.slex --mode secure slex validate ./artifact.slex --mode trusted --strict ``` Conformance validates source shape, logic profile diagnostics, capability checks, and warning stability. It is not a visual renderer screenshot test. ## Diagnostic Codes Clients use `code`, `path`, and `value` for program logic. `message` is for display. | Code | Severity | Meaning | |---|---|---| | `syntax` | error | JavaScript object literal parsing failed. Returned as `diagnostic.code`, not a warning. | | `unsupported_protocol` | warning | The optional `slex` marker does not match the supported protocol version. | | `invalid_component_key` | warning | A component key does not match the `type:identifier` shape. | | `invalid_directive_type` | warning | A structural directive such as `$if`, `$for`, or `$key` has an invalid value type. | | `unknown_component` | warning | The component type is not present in the generated component catalog. | | `unknown_prop` | warning | A component prop is not declared by that component's public spec. | | `unknown_std_member` | warning | A logic expression references a `std.*` helper outside the published capability catalog. | | `unknown_api_member` | warning | A logic expression references an `api.*` member outside the secure runtime capability catalog. | | `native_secure_capability` | warning | Secure mode source uses native browser capability names such as `fetch`, timers, or `WebSocket`; use policy-gated `api.*` instead. | | `reserved_context_shadowing` | warning | `g` keys or component identifiers shadow reserved expression context names. | Paths refer to the parsed source tree, for example `g.load` or `layout.text:value.$text`. If parsing fails, validation can still return source-level usage warnings, but not parsed-tree paths. ## Conformance Fixture Contract `slex-conformance.json` contains `valid`, `warning`, and `invalid` fixtures. Each fixture has an `id`, `mode`, source text, and an `expected` object. - `expected.ok` is the validator success state. - `expected.warnings` is the warning set for the fixture. The runner fails if an expected warning is missing or if an extra warning appears. - Warning matching uses `code`, and when present also `path` and `value`. - `expected.diagnostic` is the expected parse diagnostic code for invalid fixtures. - Fixture IDs stay stable. If behavior changes, add a new fixture ID. The conformance suite checks source validation semantics only. It does not assert component screenshots, browser layout, CSS output, or host adapter lifecycle behavior. ## Versioning Policy SlexKit exposes separate version fields: - `packageVersion`: npm package version, from `package.json`. - `protocolVersion`: accepted Slex source protocol marker, `0.1`. - `schemaVersion`: generated artifact schema generation, using date-style values. - `logicProfileVersion`: expression, context, stdlib, and secure capability profile version. Compatible package releases may update catalog hashes, add components or props, add examples, or improve messages without changing `protocolVersion`. Changes that alter source interpretation, remove or rename diagnostic codes, change expression semantics, or change secure capability behavior require a protocol or logic profile review. Artifact hashes are for cache invalidation, not semantic versioning. ## Difference From A2UI A2UI describes cross-platform declarative UI. SlexKit describes Markdown-embedded, stateful, executable UI artifacts; the host chooses trusted runtime or secure runtime. JSON Schema describes the envelope and catalog. The JavaScript expression profile is part of the standard because local logic and state are part of the artifact. --- # ToolHost URL: /docs/reference/toolhost Raw Markdown: /docs/reference/toolhost.md Source: site/content/reference/toolhost/en-US.md --- title: ToolHost category: Reference status: ready order: 70 summary: "Structured user-input UI for confirmations, choices, forms, and templates." slexkitRenderMode: component --- # ToolHost ToolHost bridges tool calls to interactive UI. When a model asks for confirmation, a choice, or form input, ToolHost renders the structured UI in the browser and returns the user's response as a `ToolResult`. ## Concepts When a model emits a tool call such as `confirm-action` or `fill-form`, ToolHost compiles it into a standard `SlexExpression` and mounts it using the core runtime. The mounted UI uses `submit:actions` to submit the user's input and settle a Promise. ToolHost is **separate from display-oriented `slex` fences**. Display components render information; ToolHost components collect structured user input and return it programmatically. ### Submit `submit:actions` reads the fields listed in `returnKeys`, calls the ToolHost runtime, and resolves the `ToolRenderHandle.promise` with a `ToolResult`. Do not use `submit` in display fences or component demos. Use `button` for ordinary interactions; use `submit:actions` only when the host is waiting for a structured tool result. ## Public API ### `renderToolCall(call, container) → ToolRenderHandle` Compiles a tool call into a SlexExpression, mounts it, and returns a handle. ```ts function renderToolCall(call: ToolCall, container: HTMLElement): ToolRenderHandle; ``` ```ts type ToolRenderHandle = { promise: Promise; // Resolves when user submits or ignores dispose: () => void; // Clean up the rendered UI }; type ToolResult = | { toolCallId?: string; toolName: string; status: "submitted"; value: Record } | { toolCallId?: string; toolName: string; status: "ignored"; value: null }; ``` **Usage:** ```js import { renderToolCall } from "slexkit"; const handle = renderToolCall( { id: "call_001", name: "confirm-action", arguments: { title: "Delete file?", description: "This action cannot be undone.", confirmLabel: "Delete", requireReason: true, }, }, document.getElementById("tool-container"), ); handle.promise.then((result) => { console.log(result.status); // "submitted" or "ignored" console.log(result.value); // { confirmed: true, reason: "Obsolete file" } handle.dispose(); }); ``` ### `registerToolTemplate(name, compiler)` Register a custom tool template. The compiler function receives the tool arguments and returns a `SlexExpression`. ```ts function registerToolTemplate(name: string, compiler: ToolTemplateCompiler): void; type ToolTemplateCompiler> = ( args: TArgs, runtime: ToolRuntime, call: ToolCall, ) => SlexExpression; type ToolRuntime = { submit: (value: Record) => void; ignore: () => void; }; ``` ## Built-in templates ### `confirm-action` Yes/no confirmation dialog. Supports an optional reason field. **Arguments (`ConfirmActionArguments`):** | Field | Type | Default | Description | |-------|------|---------|-------------| | `title` | `string` | `"Confirm action"` | Dialog title | | `description` | `string` | — | Optional explanation text | | `confirmLabel` | `string` | `"Confirm"` | Submit button label | | `ignoreLabel` | `string` | `"Ignore"` | Cancel button label | | `requireReason` | `boolean` | `false` | Show a reason text input | | `reasonLabel` | `string` | `"Reason"` | Label for the reason input | | `reasonPlaceholder` | `string` | `"Add a reason"` | Placeholder for the reason input | **Result value:** | Key | Type | Description | |-----|------|-------------| | `confirmed` | `boolean` | Always `true` when submitted | | `reason` | `string` | User's reason text (only if `requireReason: true`) | **Example:** ```js renderToolCall({ name: "confirm-action", arguments: { title: "Delete project?", description: "This will permanently delete all files.", confirmLabel: "Delete", requireReason: true, }, }, container); ``` ### `choose-options` / `option-list` Single or multi-select option list. `option-list` is an alias for `choose-options` — behavior is identical. **Arguments (`ChooseOptionsArguments` / `OptionListArguments`):** | Field | Type | Default | Description | |-------|------|---------|-------------| | `title` | `string` | `"Choose options"` | Dialog title | | `description` | `string` | — | Optional explanation text | | `options` / `items` | `OptionListItem[]` | `[]` | List of selectable items | | `multiple` | `boolean` | `true` | Allow multiple selection | | `selected` | `string[]` | auto | Pre-selected item IDs | | `minSelected` | `number` | `0` | Minimum required selections | | `maxSelected` | `number` | `Infinity` | Maximum allowed selections | | `submitLabel` | `string` | `"Submit"` | Submit button label | | `ignoreLabel` | `string` | `"Ignore"` | Cancel button label | **OptionListItem:** | Field | Type | Description | |-------|------|-------------| | `label` | `string` | Display text (required) | | `id` | `string` | Unique identifier (defaults to `value` or index) | | `value` | `string` | Submitted value (defaults to `id`) | | `description` | `string` | Secondary text shown after label | | `selected` | `boolean` | Pre-selected state | | `disabled` | `boolean` | Disabled state | **Rendering:** - When `multiple: true` (default): renders **checkboxes** - When `multiple: false`: renders a **radio group** **Result value:** | Key | Type | Description | |-----|------|-------------| | `selected` | `string[]` | IDs of selected items | **Example:** ```js renderToolCall({ name: "choose-options", arguments: { title: "Select dependencies", options: [ { id: "react", label: "React", description: "UI library" }, { id: "vue", label: "Vue", description: "Progressive framework" }, { id: "svelte", label: "Svelte", description: "Compiled framework", selected: true }, ], multiple: true, minSelected: 1, maxSelected: 2, }, }, container); ``` ### `fill-form` Multi-field form with various field types. **Arguments (`FillFormArguments`):** | Field | Type | Default | Description | |-------|------|---------|-------------| | `title` | `string` | `"Fill form"` | Form title | | `description` | `string` | — | Optional explanation text | | `fields` | `FormField[]` | `[]` | Form field definitions | | `values` | `Record` | — | Initial field values | | `submitLabel` | `string` | `"Submit"` | Submit button label | | `ignoreLabel` | `string` | `"Ignore"` | Cancel button label | **FormField:** | Field | Type | Default | Description | |-------|------|---------|-------------| | `name` | `string` | (required) | Field name (used as key in result value) | | `type` | `FormFieldType` | `"text"` | Field type | | `label` | `string` | `name` | Display label | | `description` | `string` | — | Help text below the field | | `placeholder` | `string` | — | Input placeholder | | `required` | `boolean` | `false` | Require non-empty value to submit | | `disabled` | `boolean` | `false` | Disable the field | | `value` | `unknown` | — | Initial value | | `options` | `Array<{label, value}>` | — | Options for `select` type | **FormFieldType:** | Type | Renders | Description | |------|---------|-------------| | `text` | `` | Free-form text | | `number` | `` | Numeric input, value is `number \| null` | | `engineering` | `` with SI prefix parsing | Accepts values like `"10kΩ"`, `"100nF"`, `"1.5MegHz"`. Parsed with `parseEngineeringNumber()`. State includes `raw`, `number`, `valid`, `prefix`, `unit`, `normalized` | | `select` | `